OAuth2整合微服务安全学习笔记

使用jwt替换默认uuid的token

授权服务器修改
  1. 授权服务器添加jwt的tokenStore及tokenEnhancer
    @Bean
    public TokenStore tokenStore(){
        return new JwtTokenStore(tokenEnhancer()) ;
    }
    // 这里注入到spring容器,否则资源服务器启动是,获取tokenKey时报404
    // 只有存在jwtTokenEnhancer的bean在容器中TokenKeyEndpoint端点才会发布
    @Bean
    public JwtAccessTokenConverter tokenEnhancer() {
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        converter.setSigningKey("123456");
        return converter ;
    }
    
  2. AuthorizationServerSecurityConfigurer配置tokenKeyAccess发布获取tokenKey端点
       @Override
        public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
            security
                // 获取tokenKey接口
                .tokenKeyAccess("isAuthenticated()")
                // 检验token是否合法,这里如果不设置,资源服务器将无法进行token校验
                .checkTokenAccess("isAuthenticated()");
        }
    
  3. AuthorizationServerEndpointsConfigurer配置使用tokenStore和tokenEnhancer
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints
            // 设置用来支持前四种授权类型的(用户名密码)
            .tokenStore(tokenStore())
            .tokenEnhancer(tokenEnhancer())
            .authenticationManager(authenticationManager)
            // 服务端如果要支持refresh则必须设置userDetailService
            // 这里用来支持refresh_token授权类型的(只有用户名)
            .userDetailsService(userDetailsService)
        ;
    }
    
网关服务器修改
  1. 添加依赖
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-oauth2</artifactId>
    </dependency>
    
  2. 删除自定义filter
  3. 添加配置
    # 获取验签token的tokenKey地址(授权服务器)
    security.oauth2.resource.jwt.key-uri=http://localhost:7777/oauth/token_key
    # 身份认证的信息
    security.oauth2.client.client-id=zuul_server
    security.oauth2.client.client-secret=secret
    
  4. 添加网关安全配置
    // 网关作为资源服务器存在
    @Configuration
    @EnableResourceServer
    public class GatewaySecurityConfig extends ResourceServerConfigurerAdapter {
          
          
        @Override
        public void configure(HttpSecurity http) throws Exception {
          
          
            http.authorizeRequests()
                .antMatchers("/oauth/**").permitAll()
                .anyRequest().authenticated();
        }
    }
    
微服务端修改
  1. 添加依赖
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-oauth2</artifactId>
    </dependency>
    
  2. 添加token验证配置(因为此时传递过来的是token而不是放在header中的明文,所以也需要校验)
    # 获取验签token的tokenKey地址(授权服务器)
    security.oauth2.resource.jwt.key-uri=http://localhost:7777/oauth/token_key
    security.oauth2.client.client-id=order_service
    security.oauth2.client.client-secret=secret
    
  3. 启动类添加@EnableResourceServer注解
    @EnableResourceServer
    @EnableDiscoveryClient
    @SpringBootApplication
    public class OrderServiceApiApplication {
          
          
        public static void main(String[] args) {
          
          
            SpringApplication.run(OrderServiceApiApplication.class, args) ;
        }
    }
    
  4. Controller请求方法通过@AuthenticationPrincipal String username获取
    @GetMapping("/hello")
    public String hello(@AuthenticationPrincipal String username){
        return "hello world" ;
    }
    
  5. 微服务之前的调用token传递我们可以使用OAuth2RestTemplate发送请求即可
    @Bean
    public OAuth2RestTemplate oAuth2RestTemplate(OAuth2ProtectedResourceDetails resource, OAuth2ClientContext context){
        return new OAuth2RestTemplate(resource, context) ;
    }
    

网关上做权限认证

  1. 在网关配置类中自定义权限校验表达式#permissionService.hasPermission(request, authentication)
    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
            .antMatchers("/oauth/**").permitAll()
            .anyRequest().access("#permissionService.hasPermission(request, authentication)");
    }
    
  2. 编写校验权限实现类
    public interface PermissionService {
          
          
        boolean hasPermission(HttpServletRequest request, Authentication authentication) ;
    }
    @Slf4j
    @Service
    public class PermissionServiceImpl implements PermissionService {
          
          
        @Override
        public boolean hasPermission(HttpServletRequest request, Authentication authentication) {
          
          
    
            return checkPermission(request, authentication);
        }
        // 校验用户的操作权限
        private boolean checkPermission(HttpServletRequest request, Authentication authentication){
          
          
           log.info("===> uri : {}", request.getRequestURI());
           log.info("===> authentication :{}", authentication);
            // 这里去校验用户是否有操作权限
            return RandomUtils.nextInt() %2 ==0 ;
        }
    }
    
  3. 编写自定义权限表达式处理器
    @Component
    public class GatewayWebSecurityExpressionHandler extends OAuth2WebSecurityExpressionHandler {
          
          
        @Autowired
        private PermissionService permissionService ;
        @Override
        protected StandardEvaluationContext createEvaluationContextInternal(Authentication authentication, FilterInvocation invocation) {
          
          
            StandardEvaluationContext evaluationContextInternal = super.createEvaluationContextInternal(authentication, invocation);
            evaluationContextInternal.setVariable("permissionService", permissionService);
            return evaluationContextInternal ;
        }
    }
    
  4. 将自定义表达式处理器配置到ResourceServerSecurityConfigurer的expressionHandler中
    @Configuration
    @EnableResourceServer
    public class GatewaySecurityConfig extends ResourceServerConfigurerAdapter {
          
          
        @Autowired
        private GatewayWebSecurityExpressionHandler gatewayWebSecurityExpressionHandler ;
        @Override
        public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
          
          
            resources.expressionHandler(gatewayWebSecurityExpressionHandler) ;
        }
        @Override
        public void configure(HttpSecurity http) throws Exception {
          
          
            http.authorizeRequests()
                .antMatchers("/oauth/**").permitAll()
                .anyRequest().access("#permissionService.hasPermission(request, authentication)");
        }
    }
    

猜你喜欢

转载自blog.csdn.net/yichengjie_c/article/details/112139013