• 微服务之间的通讯安全(二)-使用JWT优化认证机制


    1、使用JWT来解决认证中存在的问题

      之前说认证中存在的问题是效率低,每次都要取认证服务器进行校验;不安全,传递用户信息是放到请求头中的明文。这两个问题的解决方案就是JWT。JWT官网扫盲连接https://jwt.io/introduction/

      因为我们之前发出去的令牌都是一些无意义的串,而JWT中可以包含一些用户信息,这样前端发请求过来,网关就不需要去认证服务器校验了,我们只需要校验这个JWT是否被串改,并且从里面将用户信息读出来就可以了,往下转发传递和服务与服务之间进行调用时,只需要传递JWT就可以了。并且Spring给我们提供了工具,不用我们自己写代码就可以完成。我们要将架构改成下图:

    2、认证服务器改造,使其发送JWT令牌

    2.1、将之前API安全-https中使用keytool生成的证书copy到resources下

    2.2、OAuth2认证服务器配置类,将tokenStore设置为JwtTokenStore,并对暴露获取令牌签名的验证密钥

    /**
     * OAuth2认证服务器配置类
     * 需要继承AuthorizationServerConfigurerAdapter类,覆盖里面三个configure方法
     * 并添加@EnableAuthorizationServer注解,指定当前应用做为认证服务器
     *
     * @author caofanqi
     * @date 2020/1/31 18:04
     */
    @Configuration
    @EnableAuthorizationServer
    public class OAuth2AuthServerConfig extends AuthorizationServerConfigurerAdapter {
    
    
        @Resource
        private AuthenticationManager authenticationManager;
    
        @Resource
        private DataSource dataSource;
    
        @Resource
        private UserDetailsService userDetailsService;
    
        /**
         * 配置授权服务器的安全性
         * checkTokenAccess:验证令牌需要什么条件,isAuthenticated():需要经过身份认证。
         * 此处的passwordEncoders是为client secrets配置的。
         * tokenKeyAccess:设置对获取令牌签名的验证密钥需要通过身份认证
         */
        @Override
        public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
            security
                    .checkTokenAccess("isAuthenticated()")
                    .passwordEncoder(new BCryptPasswordEncoder())
                    .tokenKeyAccess("isAuthenticated()");
        }
    
    
        /**
         * 配置客户端服务
         */
        @Override
        public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
            //从数据库中读取
            clients.jdbc(dataSource);
        }
    
        /**
         * 配置授权服务器终端的非安全特征
         * authenticationManager 校验用户信息是否合法
         * tokenStore:token存储
         * userDetailsService:配合刷新令牌使用
         * tokenEnhancer:令牌增强器
         */
        @Override
        public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
            endpoints
                    .authenticationManager(authenticationManager)
    //                .tokenStore(new JdbcTokenStore(dataSource))
                    .tokenStore(new JwtTokenStore(jwtTokenEnhancer()))
                    .tokenEnhancer(jwtTokenEnhancer())
                    .userDetailsService(userDetailsService);
        }
    
    
        /**
         *  jwt令牌增强器,使用KeyPair提高安全度。
         *  声明为spring bean是为了让资源服务器可以获取令牌签名的验证密钥 ,TokenKeyEndpoint类中的 /oauth/token_key
         */
        @Bean
        public JwtAccessTokenConverter jwtTokenEnhancer() {
            JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
            //jwtAccessTokenConverter.setSigningKey("123456");
            KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(new ClassPathResource("cfq.key"), "123456".toCharArray());
            jwtAccessTokenConverter.setKeyPair(keyStoreKeyFactory.getKeyPair("cfq"));
            return jwtAccessTokenConverter;
        }
    
    }

    2.3、启动资源服务器获取令牌

      可以发现,我们现在获取到的令牌比以前长了,我们将他复制到jwt官网,可以看到如下,解析后JWT的PAYLOAD中存放这一些数据,aud:该令牌可以访问的资源服务器,user_name:申请令牌的用户,scope:令牌的scope,exp:令牌的过期时间,authorities:申请令牌用户的角色信息,client_id:申请令牌的客户端id,jti:相当于该令牌的id。当然,我们也可以在这里面加入一些信息,但是不建议,因为jwt只是防篡改,任何人都能看到里面的数据,往里面加入一些业务信息,有可能导致信息泄漏。

    3、网关和资源服务器改造

    3.1、在网关上对JWT进行认证,不再向认证服务器发请求认证

      3.1.1、将之前的一系列过滤器删掉,因为除了流控和审计,剩下的SpringSecurity和SpringSecurityOauth都为我们提供了,我们直接用就好了

      3.1.2、引入oauth2依赖

            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-oauth2</artifactId>
            </dependency>

      3.1.3、application.yml配置获取令牌签名的验证密钥地址,因为认证服务器设置了需要认证,我们还要配上client-id和client-secret

    server:
      port: 9010
    
    zuul:
      routes:
        token:
          url: http://auth.caofanqi.cn:9020
          path: /token/**
        order:
          url: http://order.caofanqi.cn:9080
          path: /order/**
      sensitive-headers:
    
    security:
      oauth2:
        client:
          client-id: gateway
          client-secret: 123456
        resource:
          jwt:
            key-uri: http://auth.caofanqi.cn:9020/oauth/token_key

      3.1.4、网关资源服务器配置,放过申请令牌请求

    /**
     * 网关资源服务器配置
     *
     * @author caofanqi
     * @date 2020/2/8 22:30
     */
    @Configuration
    @EnableResourceServer
    public class GatewayResourceServerConfig extends ResourceServerConfigurerAdapter {
    
    
        @Override
        public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
            resources.resourceId("gateway");
        }
    
        @Override
        public void configure(HttpSecurity http) throws Exception {
            http
                    .authorizeRequests()
                    //放过申请令牌的请求不需要身份认证
                    .antMatchers("/token/**").permitAll()
                    .anyRequest().authenticated();
        }
    
    }

      3.1.5、Order和Price资源服务器配置,也是需要引入oauth2依赖,配置获取令牌签名的验证密钥地址,client-id和client-secret,但是调用服务的请求需要由RestTemplate替换为OAuth2RestTemplate,这样就会将在我们调用别的服务时,将jwt一并传递过去。获取用户信息,通过@AuthenticationPrincipal注解进行获取。

    /**
     * 订单微服务
     *
     * @author caofanqi
     * @date 2020/1/31 14:22
     */
    @EnableResourceServer
    @SpringBootApplication
    public class OrderApiApplication {
    
    
        public static void main(String[] args) {
            SpringApplication.run(OrderApiApplication.class,args);
        }
    
        /**
         *  将OAuth2RestTemplate声明为spring bean,OAuth2ProtectedResourceDetails,OAuth2ClientContext springboot会自动帮我们注入
         */
        @Bean
        public OAuth2RestTemplate oAuth2RestTemplate(OAuth2ProtectedResourceDetails resource, OAuth2ClientContext context){
            return new OAuth2RestTemplate(resource,context);
        }
    
    }
    /**
     * 订单控制层
     *
     * @author caofanqi
     * @date 2020/1/31 14:26
     */
    @Slf4j
    @RestController
    @RequestMapping("/orders")
    public class OrderController {
    
        @Resource
        private OAuth2RestTemplate oAuth2RestTemplate;
    
        @PostMapping
        public OrderDTO create(@RequestBody OrderDTO orderDTO, @AuthenticationPrincipal String username) {
            log.info("username is :{}", username);
            PriceDTO price = oAuth2RestTemplate.getForObject("http://127.0.0.1:9070/prices/" + orderDTO.getProductId(), PriceDTO.class);
            log.info("price is : {}", price.getPrice());
            return orderDTO;
        }
    
    
        @GetMapping("/{id}")
        public OrderDTO get(@PathVariable Long id, @AuthenticationPrincipal String username) {
            log.info("username is :{}", username);
            OrderDTO orderDTO = new OrderDTO();
            orderDTO.setId(id);
            orderDTO.setProductId(5 * id);
            return orderDTO;
        }
    
    }

      3.1.6、测试,需要先启动认证服务器,因为各资源服务器需要在启动时获取令牌签名的验证密钥。

      获取令牌,通过网关创建订单,报错403,是因为我们通过webApp申请的令牌可以访问的资源服务器没有添加gateway,

    我们可以在resource_ids添加上gateway,也可以什么都不填,这样发出去的令牌就可以访问所有的资源服务器了。

    我们这里,什么都不填写,然后重新申请令牌,再次通过网关创建订单,可以正常创建,并且在订单服务和价格服务中可以获取到username

      

      我们传一个错误的令牌或者不传令牌进行访问,会返回401,这说明我们之前写的逻辑SpringSecurity和SpringSecurityOauth都已经帮我们实现好了。

     

     项目源码:https://github.com/caofanqi/study-security/tree/dev-jwt-authentication

  • 相关阅读:
    谣言检测——(PSA)《Probing Spurious Correlations in Popular EventBased Rumor Detection Benchmarks》
    谣言检测(GACL)《Rumor Detection on Social Media with Graph Adversarial Contrastive Learning》
    谣言检测——(BiGCN)《Rumor Detection on Social Media with BiDirectional Graph ConvolutionalNetworks》
    谣言检测()——《Debunking Rumors on Twitter with Tree Transformer》
    谣言检测——(GLAN)《Jointly embedding the local and global relations of heterogeneous graph for rumor detection》
    谣言检测——(EBGCN)《Towards Propagation Uncertainty: Edgeenhanced Bayesian Graph Convolutional Networks for Rumor Detection》
    代码
    第五章学习笔记
    cat userlist
    20201307梁辰鱼第11章学习总结
  • 原文地址:https://www.cnblogs.com/caofanqi/p/12285760.html
Copyright © 2020-2023  润新知