前言

《Spring Microservices in Action》

《Spring Cloud Alibaba 微服务原理与实战》

《B站 尚硅谷 SpringCloud 框架开发教程 周阳》

JWT 为 OAuth2 令牌提供规范标准,并且可以自定义 JWT 令牌;


1. JWT 令牌存储基础知识

1.1 JSON Web Token

  • OAuth2 是一个基于令牌的验证框架,但它并没有为如何定义其规范中的令牌提供任何标准;
  • 由此出现了 JSON Web Token ( JWT )新标准;
  • JWT是因特网工程任务组( Internet Engineering Task Force, IETF )提出的开放标准(RFC-7519 ),旨在为 0Auth2令牌提供标准结构
    • JWT 令牌的特点:小巧、密码签名、自包含、可扩展;
  • Spring Cloud Security 为 JWT 提供了开箱即用的支持;

2. 构建使用 JWT 令牌存储的 OAuth2 服务器

2.1 引入 pom.xml 依赖文件

  1. <!-- JWT OAuth2 库 -->
  2. <dependency>
  3. <groupid>org.springframework.security</groupid>
  4. <artifactid>spring-security-jwt</artifactid>
  5. </dependency>
  6. <!--security 通用安全库-->
  7. <dependency>
  8. <groupid>org.springframework.cloud</groupid>
  9. <artifactid>spring-cloud-security</artifactid>
  10. </dependency>
  11. <!--oauth2.0-->
  12. <dependency>
  13. <groupId>org.springframework.security.oauth</groupId>
  14. <artifactId>spring-security-oauth2</artifactId>
  15. </dependency>

2.2 创建 JWT 令牌存储

在 security 包或 config 包下;

  1. @Configration
  2. public class JWTTokenStoreConfig{
  3. @Autowired
  4. private ServiceConfig serviceConfig;
  5. @Bean
  6. public TokenStore tokenStore(){
  7. return new JwtTokenStore(jwtAccessTokenConverter());
  8. }
  9. //用于从出示给服务的令牌中读取数据
  10. @Bean
  11. @Primary //用于告诉 Spring,如果有多个特定类型的 bean(本例中为 DefaultTokenService),那么使用 @Primary 标注的 Bean 类型自动注入
  12. public DefaultTikenServices tokenServices(){
  13. DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
  14. defaultTokenServices.setTokenStore(tokenStore());
  15. defaultTokenServices.setSupportRefreshToken(true);
  16. return defaultTokenServices;
  17. }
  18. @Bean
  19. public JwtAccessTokenConverter jwtAccessTokenConverter(){
  20. //在 JWT 和 OAuth2 服务器之间充当翻译
  21. JwtAccessTokenConverter conver = new JwtAccessTokenConverter();
  22. //定义将用于签署令牌的签名密钥
  23. conver.setSigningKey(serviceConfig.getJwtSigningKey());
  24. }
  25. @Bean
  26. public TokenEnhancer jwtTokenEnhancer(){
  27. return new JWTTokenEnhancer();
  28. }
  29. }
  • 该类用于定义 Spring 将如何管理 JWT 令牌的创建、签名和翻译;

2.3 将 JWT 挂载到验证服务中

  1. @Configuration
  2. public class JWTOAuth2Config extends AuthorizationServerConfigurerAdapter {
  3. @Autowired
  4. private AuthenticationManager authenticationManager;
  5. @Autowired
  6. private UserDetailsService userDetailsService;
  7. @Autowired
  8. private TokenStore tokenStore;
  9. @Autowired
  10. private DefaultTokenServices tokenServices;
  11. @Autowired
  12. private JwtAccessTokenConverter jwtAccessTokenConverter;
  13. @Autowired
  14. private TokenEnhancer jwtTokenEnhancer;
  15. @Override
  16. public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
  17. TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
  18. tokenEnhancerChain.setTokenEnhancers(Arrays.asList(jwtTokenEnhancer, jwtAccessTokenConverter));
  19. endpoints.tokenStore(tokenStore) //JWT,5.2中定义的命令存储将在这里注入
  20. .accessTokenConverter(jwtAccessTokenConverter) //JWT,钩子,用于告诉 Spring Security OAuth2 代码使用 JWT
  21. .tokenEnhancer(tokenEnhancerChain) //JWT
  22. .authenticationManager(authenticationManager)
  23. .userDetailsService(userDetailsService);
  24. }
  25. @Override
  26. public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
  27. clients.inMemory()
  28. .withClient("eagleeye")
  29. .secret("thisissecret")
  30. .authorizedGrantTypes("refresh_token", "password", "client_credentials")
  31. .scopes("webclient", "mobileclient");
  32. }
  33. }

3. 在受保护服务中使用 JWT

3.1 引入 pom.xml 依赖文件

  • 同 OAuth2 服务器依赖;
  1. <!-- JWT OAuth2 库 -->
  2. <dependency>
  3. <groupid>org.springframework.security</groupid>
  4. <artifactid>spring-security-jwt</artifactid>
  5. </dependency>
  6. <!--security 通用安全库-->
  7. <dependency>
  8. <groupid>org.springframework.cloud</groupid>
  9. <artifactid>spring-cloud-security</artifactid>
  10. </dependency>
  11. <!--oauth2.0-->
  12. <dependency>
  13. <groupId>org.springframework.security.oauth</groupId>
  14. <artifactId>spring-security-oauth2</artifactId>
  15. </dependency>

3.2 在受保护服务中创建 JWTTokenStoreConfig 类

  • 同本篇《5.2 创建 JWT 令牌存储》;
  1. @Configuration
  2. public class JWTTokenStoreConfig {
  3. @Autowired
  4. private ServiceConfig serviceConfig;
  5. //JWT
  6. @Bean
  7. public TokenStore tokenStore() {
  8. return new JwtTokenStore(jwtAccessTokenConverter());
  9. }
  10. //JWT
  11. @Bean
  12. @Primary
  13. public DefaultTokenServices tokenServices() {
  14. DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
  15. defaultTokenServices.setTokenStore(tokenStore());
  16. defaultTokenServices.setSupportRefreshToken(true);
  17. return defaultTokenServices;
  18. }
  19. //JWT
  20. @Bean
  21. public JwtAccessTokenConverter jwtAccessTokenConverter() {
  22. JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
  23. converter.setSigningKey(serviceConfig.getJwtSigningKey());
  24. return converter;
  25. }
  26. }

3.3 创建自定义的 RestTemplate 类以注入 JWT 令牌

可以在主程序类里,也可以在主程序类所在包及其子包里;

  1. @Primary
  2. @Bean
  3. public RestTemplate getCustomRestTemplate() {
  4. RestTemplate template = new RestTemplate();
  5. List interceptors = template.getInterceptors();
  6. if (interceptors == null) {
  7. //UserContextInterceptor 会将 Authorization 首部注入每个 REST 调用
  8. template.setInterceptors(Collections.singletonList(new UserContextInterceptor()));
  9. } else {
  10. interceptors.add(new UserContextInterceptor());
  11. template.setInterceptors(interceptors);
  12. }
  13. return template;
  14. }

3.4 UserContextInterceptor 将注入 JWT 令牌到 REST 调用

  1. public class UserContextInterceptor implements ClientHttpRequestInterceptor {
  2. @Override
  3. public ClientHttpResponse intercept(
  4. HttpRequest request, byte[] body, ClientHttpRequestExecution execution)
  5. throws IOException {
  6. HttpHeaders headers = request.getHeaders();
  7. headers.add(UserContext.CORRELATION_ID, UserContextHolder.getContext().getCorrelationId());
  8. //将授权令牌添加到 HTTP 首部
  9. headers.add(UserContext.AUTH_TOKEN, UserContextHolder.getContext().getAuthToken());
  10. return execution.execute(request, body);
  11. }
  12. }

3.5 扩展 JWT 令牌(也叫自定义、增强)

  • 通过向被保护服务添加一个 Spring OAuth2 令牌增强类,扩展 JWT 令牌;
  1. //需要扩展 TokenEnhancer 类
  2. public class JWTTokenEnhancer implements TokenEnhancer {
  3. @Autowired
  4. private OrgUserRepository orgUserRepo;
  5. //基于用户名查找用户的组织 ID
  6. private String getOrgId(String userName){
  7. UserOrganization orgUser = orgUserRepo.findByUserName( userName );
  8. return orgUser.getOrganizationId();
  9. }
  10. //进行这种增强,需要覆盖 enhance() 方法
  11. @Override
  12. public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
  13. Map<String, Object> additionalInfo = new HashMap<>();
  14. String orgId = getOrgId(authentication.getName());
  15. additionalInfo.put("organizationId", orgId);
  16. //所有附加属性放在 HashMap 中,并设置在传入该方法的 accessToken 变量上
  17. ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo);
  18. return accessToken;
  19. }
  20. }

3.6 告诉被保护服务使用 JWTTokenEnhancer 类

  • 首先需要公开 TokenEnhancer 类;
  1. @Bean
  2. public TokenEnhancer jwtTokenEnhancer() {
  3. return new JWTTokenEnhancer();
  4. }
  • TokenEnhancer 类挂钩在验证服务中。类似《2.3 将 JWT 挂载到验证服务中》;
  1. @Configuration
  2. public class JWTOAuth2Config extends AuthorizationServerConfigurerAdapter {
  3. @Autowired
  4. private AuthenticationManager authenticationManager;
  5. @Autowired
  6. private UserDetailsService userDetailsService;
  7. @Autowired
  8. private TokenStore tokenStore;
  9. @Autowired
  10. private DefaultTokenServices tokenServices;
  11. @Autowired
  12. private JwtAccessTokenConverter jwtAccessTokenConverter;
  13. //自动装配 TokenEnhancer 类
  14. @Autowired
  15. private TokenEnhancer jwtTokenEnhancer;
  16. @Override
  17. public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
  18. //允许开发人员挂钩多个令牌增强器
  19. TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
  20. tokenEnhancerChain.setTokenEnhancers(Arrays.asList(jwtTokenEnhancer, jwtAccessTokenConverter));
  21. endpoints.tokenStore(tokenStore) //JWT
  22. .accessTokenConverter(jwtAccessTokenConverter) //JWT
  23. .tokenEnhancer(tokenEnhancerChain) //JWT,将令牌增强器链挂钩到传入 configure() 方法的 endpoints 参数
  24. .authenticationManager(authenticationManager)
  25. .userDetailsService(userDetailsService);
  26. }
  27. @Override
  28. public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
  29. clients.inMemory()
  30. .withClient("eagleeye")
  31. .secret("thisissecret")
  32. .authorizedGrantTypes("refresh_token", "password", "client_credentials")
  33. .scopes("webclient", "mobileclient");
  34. }
  35. }

3.7 使用 JJWT 库在 Zuul 网关里解析 JWT 令牌中解析自定义字段

以下配置均在在 Zuul 网关服务里进行;

3.7.1 在 Zuul 网关里添加 pom.xml 依赖文件

  1. <dependency>
  2. <groupId>io.jsonwebtoken</groupId>
  3. <artifactId>jjwt</artifactId>
  4. <version>0.7.0</version>
  5. </dependency>

3.7.2 添加一个新方法,用来解析 serviceId

  1. private String getOrganizationId(){
  2. String result="";
  3. if (filterUtils.getAuthToken()!=null){
  4. //从 HTTP 首部 Authorization 解析出令牌
  5. String authToken = filterUtils.getAuthToken().replace("Bearer ","");
  6. try {
  7. //传入用于签署令牌的签名密钥,使用 JWTS 类解析令牌
  8. Claims claims = Jwts.parser()
  9. .setSigningKey(serviceConfig.getJwtSigningKey().getBytes("UTF-8"))
  10. .parseClaimsJws(authToken).getBody();
  11. //从令牌中提取 xxxId
  12. result = (String) claims.get("organizationId");
  13. }
  14. catch (Exception e){
  15. e.printStackTrace();
  16. }
  17. }
  18. return result;
  19. }

最后

新人制作,如有错误,欢迎指出,感激不尽!
欢迎关注公众号,会分享一些更日常的东西!
如需转载,请标注出处!

微服务架构 | 7.2 构建使用 JWT 令牌存储的 OAuth2 安全认证的更多相关文章

  1. 微服务架构 - 基于Harbor构建本地镜像仓库

    之前写过<搭建docker本地镜像仓库并提供权限校验及UI界面>文章,然后有同仁评论道这样做太复杂了,如果Harbor来搭建会更简单同时功能也更强大.于是抽时间研究了基于Harbor构建本 ...

  2. 微服务架构 | 7.1 基于 OAuth2 的安全认证

    目录 前言 1. OAuth2 基础知识 1.1 安全性的 4 个组成部分 1.2 OAuth2 的工作原理 1.3 OAuth2 规范的 4 种类型的授权 1.4 OAuth2 的优势 1.5 OA ...

  3. Net分布式系统之五:微服务架构

    因工作较忙,抽时间将框架遇到的问题和框架升级设计进行记录. 一.背景&问题 之前框架是一个基于SOA思想设计的分布式框架.各应用通过服务方式提供使用,服务之间通信是RPC方式调用,具体实现基于 ...

  4. 使用微服务架构思想,设计部署OAuth2.0授权认证框架

    1,授权认证与微服务架构 1.1,由不同团队合作引发的授权认证问题 去年的时候,公司开发一款新产品,但人手不够,将B/S系统的Web开发外包,外包团队使用Vue.js框架,调用我们的WebAPI,但是 ...

  5. 【转】「Chris Richardson 微服务系列」微服务架构的优势与不足

    Posted on 2016年5月4日 编者的话|本文来自 Nginx 官方博客,是微服务系列文章的第一篇,主要探讨了传统的单体式应用的不足,以及微服务架构的优势与挑战. 作者介绍:Chris Ric ...

  6. 微服务实战(一):微服务架构的优势与不足 - DockOne.io

    原文:微服务实战(一):微服务架构的优势与不足 - DockOne.io [编者的话]本文来自Nginx官方博客,是微服务系列文章的第一篇,主要探讨了传统的单体式应用的不足,以及微服务架构的优势与挑战 ...

  7. 微服务架构 技能图谱skill-map

    # 微服务架构 技能图谱 ## 理论基础### 概念#### 多微合适 - 非代码函数 - 非重写时间 - 适合团队最重要 - 独立业务属性 - 全功能团队 #### 进程隔离 - 服务运行在独立的进 ...

  8. 基于spring boot2.0+spring security +oauth2.0+ jwt微服务架构

    github地址:https://github.com/hankuikuide/microservice-spring-security-oauth2 项目介绍 该项目是一个演示项目,主要演示了,基于 ...

  9. Spring Cloud构建微服务架构(一)服务注册与发现

    Spring Cloud简介 Spring Cloud是一个基于Spring Boot实现的云应用开发工具,它为基于JVM的云应用开发中的配置管理.服务发现.断路器.智能路由.微代理.控制总线.全局锁 ...

随机推荐

  1. 【剑指Offer】平衡二叉树 解题报告(Python & C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 解题方法 日期 题目地址:https://www.nowcoder.co ...

  2. YAPTCHA(hdu2973)

    YAPTCHA Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Su ...

  3. 1281 - New Traffic System

    1281 - New Traffic System   PDF (English) Statistics Forum Time Limit: 2 second(s) Memory Limit: 32 ...

  4. 论文翻译:2019_Deep Neural Network Based Regression Approach for A coustic Echo Cancellation

    论文地址:https://dl.acm.org/doi/abs/10.1145/3330393.3330399 基于深度神经网络的回声消除回归方法 摘要 声学回声消除器(AEC)的目的是消除近端传声器 ...

  5. 第十一个知识点:DLP,CDH和DDH问题都是什么?

    第十一个知识点:DLP,CDH和DDH问题都是什么 这是第11篇也是数学背景的第二篇.主要关注群操作如何被用于设计密码基础. 就像你现在知道的那样,密码学经常依赖于'难问题'.这也就是说,如果我们假设 ...

  6. Linux环境下Django App部署到XAMPP上

    Django App部署到XAMPP上 准备工作 首先一定要保证自己的代码在本地可以运行! 同时在服务器上把需要的库,什么数据库之类的都装好! 源码安装mod_wsgi 从mod_wsgi的gitgu ...

  7. JWT+SpringBoot实战

    往期内容:JWT - 炒焖煎糖板栗 - 博客园 (cnblogs.com) JWT可以理解为一个加密的字符串,里面由三部分组成:头部(Header).负载(Payload).签名(signature) ...

  8. Android 常见对话框的简单使用(提示信息对话框、单选多选对话框、自定义对话框)

    目录 一.提示信息对话框: 二.单选对话框: 三.多选对话框: 四.自定义对话框: 演示项目完整代码: 一.提示信息对话框: //显示提示消息对话框 private void showMsgDialo ...

  9. 《MySQL数据操作与查询》- 返校复习课练习题,创建数据库user_system,创建数据表user及user_ext

    一.其它(共18题,100分) 1.创建数据库user_system CREATE DATABASE user_system 2.在数据库user_system中创建数据表user及user_ext, ...

  10. Linux-saltstack-2 saltstack的基本使用

    @ 目录 一.salt命令的基本使用 1.基本语法 例子: 2.salt的常用参数 (1)-S(大写):通过IP或者是网段匹配被管理主机 (2)-E:通过正则匹配主机 (3)-L: 匹配多个主机 (4 ...