spring security Oauth2 入门示例之认证、资源分离

依赖

认证、资源服务器共用一个依赖

<artifactId>spring-security-oauth2-jjwt-demoartifactId>
<packaging>pompackaging>
<modules>
    <module>authorization-servermodule>
    <module>resource-servermodule>
modules>
<dependencies>
    <dependency>
        <groupId>org.springframework.cloudgroupId>
        <artifactId>spring-cloud-starter-oauth2artifactId>
    dependency>
    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-securityartifactId>
    dependency>
    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-webartifactId>
    dependency>
    <dependency>
        
        <groupId>org.springframework.securitygroupId>
        <artifactId>spring-security-jwtartifactId>
        <version>1.0.9.RELEASEversion>
    dependency>
dependencies>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-dependenciesartifactId>
            <version>Hoxton.SR8version>
            <type>pomtype>
            <scope>importscope>
        dependency>
    dependencies>
dependencyManagement>

认证服务器

配置

认证服务器的配置主要包括四点:启用授权服务、客户端详情服务、配置令牌的访问端点和令牌服务、配置令牌端点的安全约束

  1. 启用授权服务:用于标识当前服务是一个授权服务 — 在配置类中增加@EnableAuthorizationServer即可

  2. 客户端详情服务: 用于配置需要认证的客户端相关信息

    // 重写AuthorizationServerConfigurerAdapter类中的configure(ClientDetailsServiceConfigurer clients)方法(注意参数),并在此方法中配置客户端信息。
    @Configuration
    @EnableAuthorizationServer
    public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
         @Override
        public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
            clients.inMemory() // 客户端信息存储位置
                	// 客户端详情
                    .withClient("client") // 客户端ID
                    .secret(passwordEncoder.encode("878412")) // 客户端密码
                    .resourceIds("user") // 客户端允许访问的资源
                    .redirectUris("http://localhost:8082/test")// 回调地址
                    .scopes("all")// 授权范围
    //                .authorizedGrantTypes("authorization_code","password","client_credentials","implicit","refresh_token") // 授权类型:授权码模式、密码模式、客户端模式、简化模式
                    .authorizedGrantTypes("authorization_code") // 授权类型。
                    .autoApprove(false);
            // 可以在and()后面配置另外一个客户端的信息.
        }
    }
    
  3. 配置令牌的访问端点和令牌服务

    // 在TokenConfig中创建令牌的存储策略(内存存储)
    @Configuration
    public class TokenConfig {
        @Bean
        public TokenStore tokenStore(){
            // 令牌存储策略:内存方式
            return new InMemoryTokenStore();
        }
    }
    
    // 
    @Configuration
    @EnableAuthorizationServer
    public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
        
         @Autowired
        private ClientDetailsService clientDetailsService;
    
        @Autowired
        private TokenStore tokenStore;
        
        // 令牌管理服务
        public AuthorizationServerTokenServices tokenServices(){
            DefaultTokenServices services = new DefaultTokenServices();
            services.setClientDetailsService(clientDetailsService); // 客户端详情服务器(第2点中已经配好的),自动注入
            services.setSupportRefreshToken(true); // 支持刷新令牌
            services.setTokenStore(tokenStore); // 令牌存储方式(在TokenConfig中配置的)
            services.setAccessTokenValiditySeconds(7200); // 令牌过期时间
            services.setRefreshTokenValiditySeconds(259200); // 刷新令牌过期时间
            return services;
        }
        
        //授权码的存储方式
        @Bean
        public AuthorizationCodeServices authorizationCodeServices(){
            return new InMemoryAuthorizationCodeServices();
        }
        
        @Autowired
        private AuthorizationCodeServices authorizationCodeServices;
        
        @Autowired
        private AuthenticationManager authenticationManager; // 认证管理器自动注入
        
        @Override
        public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
            // 令牌访问端点,包括:/authrize、/token、/confirm_access、/error、/check_token、/token_key(前缀为/oauth)
            endpoints
                    .authenticationManager(authenticationManager) // 认证管理器(参见后面的说明)
                    .authorizationCodeServices(authorizationCodeServices) // 授权码服务(参见上面authorizationCodeServices方法的定义)
                    .tokenServices(tokenServices()) // 令牌管理服务(见上面的方法定义)
                    .allowedTokenEndpointRequestMethods(HttpMethod.POST);
        }
    }
    

    认证管理器定义

    // 配置SecurityConfig ,并在此配置文件中重写WebSecurityConfigurerAdapter类中的authenticationManagerBean方法创建出AuthenticationManager对象,同时还需要配置UserDetailsService
    @Configuration
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
        @Bean
        public PasswordEncoder passwordEncoder() {
            return new BCryptPasswordEncoder();
        }
        @Bean
        @Override
        public AuthenticationManager authenticationManagerBean() throws Exception {
            return super.authenticationManagerBean();
        }
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.csrf().disable()
                    .authorizeRequests()
                    .antMatchers("/login/**").permitAll()
                    .anyRequest().authenticated()
                    .and()
                    .formLogin();
        }
    }
    // 实现 UserDetailsService
    @Service
    public class UserService implements UserDetailsService {
    
        @Autowired
        private PasswordEncoder passwordEncoder;
    
        @Override
        public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
    
            String pwd = passwordEncoder.encode("123456");
            return new User(username, pwd,
                    AuthorityUtils.commaSeparatedStringToAuthorityList("admin,sysadmin"));
        }
    }
    
    
  4. 配置令牌端点的安全约束

    令牌的端点服务允许如何方法

    @Configuration
    @EnableAuthorizationServer
    public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
    	@Override
        public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
            security.tokenKeyAccess("permitAll()")
                    .checkTokenAccess("permitAll()")
                    .allowFormAuthenticationForClients();
        }
    }
    

测试使用

  1. 获取授权码

    http://localhost:8081/oauth/authorize?response_type=code&client_id=client&redirect_uri=http://localhost:8082/test&scope=all

    参数说明:

    ​ response_type: code --授权码

    ​ client_id: client – AuthorizationServerConfig配置文件中配置的withClient

    ​ redirect_uri:http://localhost:8082/test – AuthorizationServerConfig配置文件中配置的redirectUris。

    ​ scope:all – 授权类型 ,AuthorizationServerConfig配置文件中配置的scopes。

    请求上面的地址后先会跳转到登录页面,使用UserService配置的账号密码登录后会跳转到授权页面,授权后才会跳转到百度,并附带授权码(本例中没有校验账号,只校验密码为123456即可,所以账号可以随意输入,密码为123456)

  2. 用获取到的授权码再去请求授权令牌(使用postman来测试)

    地址:http://localhost:8081/oauth/token

    参数:

    参数名
    grant_type authorization_code
    client_id client
    client_secret 客户端设置的密码
    redirect_uri http://localhost:8082/test
    scope all
    code 上面获取到的授权吗

资源服务器

配置

@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        resources
                .resourceId("user")
                .tokenServices(tokenServices())
                .stateless(true);
    }

    // token校验方法
    public ResourceServerTokenServices tokenServices(){
        RemoteTokenServices remoteTokenServices = new RemoteTokenServices();
        remoteTokenServices.setCheckTokenEndpointUrl("http://localhost:8081/oauth/check_token");
        remoteTokenServices.setClientId("client");
        remoteTokenServices.setClientSecret("878412");
        return remoteTokenServices;
    }
}

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/test/**")
                .permitAll()
                .anyRequest().authenticated()
                .and()
                .formLogin().permitAll()
                .and()
                .csrf()
                .disable()
        ;
    }
}

资源

@RestController
@RequestMapping("/user")
public class UserController {

    @RequestMapping("getCurrentUser")
    public Object getCurrentUser(Authentication authentication){
        return authentication.getPrincipal();
    }
}

测试使用

3.依据授权令牌请求资源

​ 地址:http://localhost:8082/user/getCurrentUser

​ 授权方式:bearer token

你可能感兴趣的:(专题教程,java,基础知识,spring,seurity,oauth2,入门示例,认证资源分离)