Spring Security OAuth 项目已经被弃用了,停止维护...
在 2020/04/15 这天,Spring 团队又宣布新起《Spring Authorization Server》项目,以继续提供对 Spring 授权服务器的支持...

1、OAuth 2.0 中的提供者角色实际上分为授权服务和资源服务,虽然它们有时驻留在同一个应用程序中,但使用 Spring Security OAuth,您可以选择将它们拆分为两个应用程序,也可以让多个资源服务共享授权服务。

2、OAuth四种模式
● 授权码模式(authorization code)
● 简化模式(implicit)
● 密码模式(resource owner password credentials)
● 客户端模式(client credentials)

3、UAA核心三个配置【AuthorizationServerConfigurerAdapter】
@EnableAuthorizationServer注解被用来配置授权服务器
ClientDetailServiceConfigurerr:配置客户端详情服务(ClientDetailsService)
AuthorizationServerEndpointsConfigurer:配置令牌端点的安全约束
AuthorizationServerSecurityConfigurer:配置令牌(token)的访问短点和令牌服务(tokenService)

4、令牌请求由 Spring MVC 控制器端点处理,对受保护资源的访问由标准 Spring Security 请求过滤器处理。为了实现 OAuth 2.0 授权服务器,Spring Security 过滤器链中需要以下端点:

AuthorizationEndpoint用于服务授权请求。默认网址:http://localhost:8080/oauth/authorize
TokenEndpoint用于服务访问令牌的请求。默认网址:http://localhost:8080/oauth/token

5、客户端模式 client_credentials
客户端向授权服务器发送自己的身份信息,请求令牌access_token
http://localhost:8080/oauth/token?client_id=client&client_secret=secret&grant_type=client_credentials Postman 请求
springsecurity和oauth的区别_客户端

6、密码模式
http://localhost:8080/oauth/token?client_id=client&client_secret=secret&grant_type=password&username=admin&password=123456
*
7、简化模式
1、http://localhost:8080/login 输入账号密码
2、再次输入如下地址,获取token
http://localhost:8080/oauth/authorize?response_type=token&client_id=client&redirect_uri=http://example.com&scope=write 
地址栏重定向如下
http://example.com/#access_token=2820363f-2e2f-4485-8892-64683895675e&token_type=bearer&expires_in=3512
*
8、授权码模式
1、http://localhost:8080/login 输入账号密码
2、再次输入如下地址,获取code
http://localhost:8080/oauth/authorize?response_type=code&client_id=client&redirect_uri=http://example.com&scope=write
地址栏重定向如下
http://example.com/?code=n9WlYp 
3、http://localhost:8080/oauth/token?grant_type=authorization_code&client_id=client_id_1&client_secret=123456&redirect_uri=http://example.com&code=n9WlYp

9、pom.xml 添加依赖

<dependency>
    <groupId>org.springframework.security.oauth.boot</groupId>
    <artifactId>spring-security-oauth2-autoconfigure</artifactId>
    <version>2.1.11.RELEASE</version>
</dependency>
<!--引入security对oauth2的支持-->
<dependency>
    <groupId>org.springframework.security.oauth</groupId>
    <artifactId>spring-security-oauth2</artifactId>
    <version>2.3.4.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

10、OAuth2AuthorizationServer.java 授权服务配置类
ClientDetailsServiceConfigurer:配置客户端详情服务(ClientDetailsService)
AuthorizationServerSecurityConfigurer:配置令牌(token)的访问短点和令牌服务(tokenService)
AuthorizationServerEndpointsConfigurer:配置令牌端点的安全约束

package com.example.demosecurity0218.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices;
import org.springframework.security.oauth2.provider.code.InMemoryAuthorizationCodeServices;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;

@Configuration
@EnableAuthorizationServer
public class MyAuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
    @Autowired
    private AuthorizationCodeServices authorizationCodeServices;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private TokenStore tokenStore;

    @Autowired
    private ClientDetailsService clientDetailsService;

    @Autowired
    private JwtAccessTokenConverter accessTokenConverter;

    // 1. 配置客户端
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
                // 添加一个client配置,指定其client_id
                .withClient("client_1")
                // 指定客户端的密码/安全码
                .secret(new BCryptPasswordEncoder().encode("secret"))
                // 指定客户端所能访问资源id清单,此处的资源id是需要在具体的资源服务器上也配置一样
                .resourceIds("salary")
                .authorizedGrantTypes("authorization_code", "password", "implicit","client_credentials","refresh_token")
                // 客户端的权限范围,此处配置为all全部即可
                .scopes("all")
                // 跳转到授权页面
                .autoApprove(false)
                // 回调地址
                .redirectUris("http://www.baidu.com");
    }

    // 2. 配置令牌访问端点
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints
                // 指定认证管理器,随后注入一个到当前类使用即可
                .authenticationManager(authenticationManager)
                // 密码模式用户信息管理
                .userDetailsService(userDetailsService)
                // 授权码服务
                .authorizationCodeServices(authorizationCodeServices)
                .authorizationCodeServices(new InMemoryAuthorizationCodeServices())
                // token服务的一个描述,可以认为是token生成细节的描述,比如有效时间多少等
                .tokenServices(tokenServices())
                // 指定token的存储方法
                .tokenStore(tokenStore)
                .allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST);
    }

    // 3. 配置令牌端点的安全策略
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security
                // 开启端口/oauth/token_key的访问权限(允许)
                .tokenKeyAccess("permitAll()")
                // 开启端口/oauth/check_token的访问权限(允许)
                .checkTokenAccess("permitAll()")
                // 允许客户端表单认证,申请令牌
                .allowFormAuthenticationForClients();
    }

    /**
     * 该方法用户获取一个token服务对象(该对象描述了token有效期等信息)
     */
    public AuthorizationServerTokenServices tokenServices() {
        // 使用默认实现
        DefaultTokenServices services = new DefaultTokenServices();
        services.setClientDetailsService(clientDetailsService);
        // 开启令牌自动刷新
        services.setSupportRefreshToken(true);
        // 令牌存储策略-内存
        //services.setTokenStore(tokenStore());
        services.setTokenStore(tokenStore);
        // 使用 JWT令牌
        services.setTokenEnhancer(accessTokenConverter);
        // 设置令牌有效时间(一般设置为2个小时),当前设置5秒钟
        services.setAccessTokenValiditySeconds(300);
        // 设置刷新令牌的有效时间 3天
        services.setRefreshTokenValiditySeconds(259200);

        return services;
    }
}

*
11、SecurityConfig.java

package com.example.demosecurity0218.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices;
import org.springframework.security.oauth2.provider.code.InMemoryAuthorizationCodeServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;

@Configuration
@EnableWebSecurity
//@EnableWebSecurity(debug = true)
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
//@Order(-1)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private static final String SIGN_KEY = "UAA";

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
                .inMemoryAuthentication()
                .withUser("admin").password(passwordEncoder().encode("123")).roles("ADMIN")
                .and()
                .withUser("user").password(passwordEncoder().encode("123")).roles("USER")
                .and()
                .withUser("king").password(passwordEncoder().encode("123")).roles("USER", "ADMIN");;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .authorizeRequests()
                .anyRequest().authenticated()
                .and()
                .formLogin();
    }

    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    // 从父类加载认证管理器
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Bean
    public TokenStore tokenStore() {
        return new InMemoryTokenStore();
    }

    @Bean
    public AuthorizationCodeServices authorizationCodeServices(){
        return new InMemoryAuthorizationCodeServices();
    }

    @Bean
    public UserDetailsService userDetailsService(){
        return new UserDetailsService() {
            @Override
            public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
                return null;
            }
        };
    }

    @Bean
    public JwtAccessTokenConverter accessTokenConverter(){
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        converter.setSigningKey(SIGN_KEY);
        return converter;
    }
}

postman获取token:
http://localhost:8080/oauth/tokenspringsecurity和oauth的区别_ide_02

检查token
http://localhost:8080/oauth/check_token
springsecurity和oauth的区别_ide_03
*
*
*