Spring Cloud基于JWT创建统一的认证服务

news2025/1/20 4:41:27

认证服务肯定要有用户信息,不然怎么认证是否为合法用户?因为是内部的调用认证,可以简单一点,用数据库管理就是一种方式。或者可以配置用户信息,然后集成分布式配置管理就完美了。

表结构

本教程中的案例把查数据库这一步骤省略了,大家可以自行补充,但是表的设计还是要跟大家讲解的。用户表的形式如图 1 所示。


图 1 用户表

相关的代码如下所示。

  1. create table auth_user(
  2. id int(4) not null,
  3. accessKey varchar(100) not null,
  4. secretKey varchar(100) not null,
  5. Primary key (id)
  6. );
  7. Alter table auth_user comment '认证用户信息表';

这里只有简单的几个字段,若大家有别的需求可以自行去扩展。代码中的 accessKey 和 secretKey 是用户身份的标识。

JWT 工具类封装

JWT 的 GitHub 地址是:https://github.com/jwtk/jjwt,依赖配置代码如下所示。

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

用工具类进行认证主要有以下几个方法:

  • 生成 Token。
  • 检查 Token 是否合法。
  • 刷新 RSA 公钥以及私钥。

生成 Token 是在进行用户身份认证之后,通过用户的 ID 来生成一个 Token,这个 Token 采用 RSA 加密的方式进行加密,Token 的内容包括用户的 ID 和过期时间。

检查 Token 则是根据调用方带来的 Token 检查是否为合法用户,就是对 Token 进行解密操作,能解密并且在有效期内表示合法,合法则返回用户 ID。

刷新 RSA 公钥及私钥的作用是防止公钥、私钥泄露,公钥、私钥一般是写死的,不过我们可以做成配置的。集成配置管理中心后,可以对公钥、私钥进行动态修改,修改之后需要重新初始化公钥、私钥的对象信息。

获取 Token 代码如下所示。

  1. /**
  2. * 获取 Token
  3. *
  4. * @param uid 用户 ID
  5. * @param exp 失效时间, 单位分钟
  6. * @return
  7. */
  8. public static String getToken(String uid, int exp) {
  9. Long endTime = System.currentTimeMillis() + 1000 * 60 * exp;
  10. return Jwts.builder().setSubject(uid).setExpiration(new Date(endTime))
  11. .signWith(SignatureAlgorithm.RS512, priKey).compact();
  12. }

检查 Token 是否合法代码如下所示。

  1. /**
  2. * 检查 Token 是否合法
  3. *
  4. * @param token
  5. * @return JWTResult
  6. */
  7. public JWTResult checkToken(String token) {
  8. try {
  9. Claims claims = Jwts.parser().setSigningKey(pubKey).parseClaimsJws(token).getBody();
  10. String sub = claims.get("sub", String.class);
  11. return new JWTResult(true, sub, "合法请求", ResponseCode.SUCCESS_CODE.getCode());
  12. } catch (ExpiredJwtException e) {
  13. // 在解析 JWT 字符串时, 如果'过期时间字段'已经早于当前时间,
  14. // 将会抛出 ExpiredJwtException 异常, 说明本次请求已经失效
  15. return new JWTResult(false, null, "token已过期 ", ResponseCode.TOKEN_TIMEOUT_CODE.getCode());
  16. } catch (SignatureException e) {
  17. // 在解析 JWT 字符串时, 如果密钥不正确, 将会解析失败, 抛出
  18. // SignatureException 异常, 说明该 JWT 字符串是伪造的
  19. return new JWTResult(false, null, "非法请求", ResponseCode.NO_AUTH_CODE.getCode());
  20. } catch (Exception e) {
  21. return new JWTResult(false, null, "非法请求", ResponseCode.NO_AUTH_CODE.getCode());
  22. }
  23. }

完整代码如下所示。

  1. /**
  2. * API调用认证工具类,采用RSA加密
  3. */
  4. public class JWTUtils {
  5. private static RSAPrivateKey priKey;
  6. private static RSAPublicKey pubKey;
  7. private static class SingletonHolder {
  8. private static final JWTUtils INSTANCE = new JWTUtils();
  9. }
  10. public synchronized static JWTUtils getInstance(String modulus, String privateExponent, String publicExponent) {
  11. if (priKey == null && pubKey == null) {
  12. priKey = RSAUtils.getPrivateKey(modulus, privateExponent);
  13. pubKey = RSAUtils.getPublicKey(modulus, publicExponent);
  14. }
  15. return SingletonHolder.INSTANCE;
  16. }
  17. public synchronized static void reload(String modulus, String privateExponent, String publicExponent) {
  18. priKey = RSAUtils.getPrivateKey(modulus, privateExponent);
  19. pubKey = RSAUtils.getPublicKey(modulus, publicExponent);
  20. }
  21. public synchronized static JWTUtils getInstance() {
  22. if (priKey == null && pubKey == null) {
  23. priKey = RSAUtils.getPrivateKey(RSAUtils.modulus, RSAUtils.private_exponent);
  24. pubKey = RSAUtils.getPublicKey(RSAUtils.modulus, RSAUtils.public_exponent);
  25. }
  26. return SingletonHolder.INSTANCE;
  27. }
  28. /**
  29. * 获取Token
  30. *
  31. * @param uid 用户ID
  32. * @param exp 失效时间,单位分钟
  33. * @return
  34. */
  35. public static String getToken(String uid, int exp) {
  36. long endTime = System.currentTimeMillis() + 1000 * 60 * exp;
  37. return Jwts.builder().setSubject(uid).setExpiration(new Date(endTime))
  38. .signWith(SignatureAlgorithm.RS512, priKey).compact();
  39. }
  40. /**
  41. * 获取Token
  42. *
  43. * @param uid 用户ID
  44. * @return
  45. */
  46. public String getToken(String uid) {
  47. long endTime = System.currentTimeMillis() + 1000 * 60 * 1440;
  48. return Jwts.builder().setSubject(uid).setExpiration(new Date(endTime))
  49. .signWith(SignatureAlgorithm.RS512, priKey).compact();
  50. }
  51. /**
  52. * 检查Token是否合法
  53. *
  54. * @param token
  55. * @return JWTResult
  56. */
  57. public JWTResult checkToken(String token) {
  58. try {
  59. Claims claims = Jwts.parser().setSigningKey(pubKey).parseClaimsJws(token).getBody();
  60. String sub = claims.get("sub", String.class);
  61. return new JWTResult(true, sub, "合法请求", ResponseCode.SUCCESS_CODE.getCode());
  62. } catch (ExpiredJwtException e) {
  63. // 在解析JWT字符串时,如果‘过期时间字段’已经早于当前时间,将会抛出ExpiredJwtException异常,说明本次请求已经失效
  64. return new JWTResult(false, null, "token已过期", ResponseCode.TOKEN_TIMEOUT_CODE.getCode());
  65. } catch (SignatureException e) {
  66. // 在解析JWT字符串时,如果密钥不正确,将会解析失败,抛出SignatureException异常,说明该JWT字符串是伪造的
  67. return new JWTResult(false, null, "非法请求", ResponseCode.NO_AUTH_CODE.getCode());
  68. } catch (Exception e) {
  69. return new JWTResult(false, null, "非法请求", ResponseCode.NO_AUTH_CODE.getCode());
  70. }
  71. }
  72. public static class JWTResult {
  73. private boolean status;
  74. private String uid;
  75. private String msg;
  76. private int code;
  77. public JWTResult() {
  78. super();
  79. }
  80. public JWTResult(boolean status, String uid, String msg, int code) {
  81. super();
  82. this.status = status;
  83. this.uid = uid;
  84. this.msg = msg;
  85. this.code = code;
  86. }
  87. public int getCode() {
  88. return code;
  89. }
  90. public void setCode(int code) {
  91. this.code = code;
  92. }
  93. public String getMsg() {
  94. return msg;
  95. }
  96. public void setMsg(String msg) {
  97. this.msg = msg;
  98. }
  99. public boolean isStatus() {
  100. return status;
  101. }
  102. public void setStatus(boolean status) {
  103. this.status = status;
  104. }
  105. public String getUid() {
  106. return uid;
  107. }
  108. public void setUid(String uid) {
  109. this.uid = uid;
  110. }
  111. }
  112. }

认证接口

认证接口用于调用方进行认证时,认证通过则返回一个加密的 Token 给对方,对方就可以用这个 Token 去请求别的服务了,认证获取 Token 代码如下所示。

  1. @PostMapping("/token")
  2. public ResponseData auth(@RequestBody AuthQuery query) throws Exception {
  3. if (StringUtils.isBlank(query.getAccessKey()) || StringUtils.isBlank(query.getSecretKey())) {
  4. return ResponseData.failByParam("accessKey and secretKey not null");
  5. }
  6. User user = authService.auth(query);
  7. if (user == null) {
  8. return ResponseData.failByParam(" 认证失败 ");
  9. }
  10. JWTUtils jwt = JWTUtils.getInstance();
  11. return ResponseData.ok(jwt.getToken(user.getId().toString()));
  12. }

认证参数代码如下所示。

  1. /**
  2. * API 用户认证参数类
  3. */
  4. public class AuthQuery {
  5. private String accessKey;
  6. private String secretKey;
  7. // get set ...
  8. }

AuthService 中的 auth 方法就是根据 accessKey 和 secretKey 判断是否有这个用户。

由于篇幅有限,请大家继续阅读以下教程:

  • 服务提供方进行调用认证
  • 服务消费方申请Token
  • Feign调用前统一申请Token传递到调用的服务中
  • RestTemplate调用前统一申请Token传递到调用的服务中
  • Zuul中传递Token到路由的服务中

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/93039.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2022-年终总结

2022年已经到了尾声&#xff0c;后半年度过的太漫长了&#xff0c;也是自己这两年来成长速度最快的一次了&#xff08;后文揭晓&#xff09; 今年的年中总结链接 上半年我沉浸在读各类技术书籍中&#xff0c;但是后半年的我几乎放弃了读书&#xff0c;转而投身到另外一个学习渠…

Linux Phy 驱动解析

文章目录1. 简介2. phy_device2.1 mdio bus2.2 mdio device2.3 mdio driver2.4 poll task2.4.1 自协商配置2.4.2 link 状态读取2.4.3 link 状态通知3. phylink3.1 phylink_create()3.2 phylink_connect_phy()3.3 phylink_start()3.3 poll task参考资料1. 简介 在调试网口驱动的…

从另外一个角度解释AUC

AUC到底代表什么呢&#xff0c;我们从另外一个角度解释AUC&#xff0c;我们先看看一个auc曲线 蓝色曲线下的面积(我的模型的AUC)比红线下的面积(理论随机模型的AUC)大得多&#xff0c;所以我的模型一定更好。 我的模型比随机模型好多少呢?理论随机模型只是对角线&#xff0c;…

加密与认证技术

加密与认证技术密码技术概述密码算法与密码体制的基本概念加密算法与解密算法秘钥的作用什么是密码密钥长度对称密码体系对称加密的基本概念典型的对称加密算法DES加密算法3DES加密算法非对称密码体系非对称加密基本概念密码技术概述 密码技术是保证网络安全的核心技术之一&am…

【windows Server 2019系列】 构建IIS服务器

个人名片&#xff1a; 对人间的热爱与歌颂&#xff0c;可抵岁月冗长&#x1f31e; Github&#x1f468;&#x1f3fb;‍&#x1f4bb;&#xff1a;念舒_C.ying CSDN主页✏️&#xff1a;念舒_C.ying 个人博客&#x1f30f; &#xff1a;念舒_C.ying Web服务器也称为WWW(World W…

电子厂测试题——难倒众多主播——大司马也才90分

一、选择题 1、1-2 ( ) A.1 B.3 C.-1 D.-3 2、|1-2|( ) A.1 B.3 C. -1 D.-3 3、1x2x3( ) A.5 B.6 C.7 D.8 4、3643( ) A.29 B.16 C.8 D.3 5、55x5( ) A.15 B.30 C.50 D.125 二、填空题(请填写阿拉伯数字) 6、110100 1000_______ 7、一个三角形砍去1个角&#…

Feign的两种最佳实践方式介绍

何谓最佳实践呢&#xff1f;就是企业中各种踩坑&#xff0c;最后总结出来的相对比较好的使用方式&#xff1b; 下面给大家介绍两种比较好的实践方案&#xff1a; 方式一&#xff08;继承&#xff09;&#xff1a;给消费者的FeignClient和提供着的Controller定义一个统一的父接…

在逆变器中驱动和保护IGBT

在逆变器中驱动和保护IGBT 介绍 ACPL-339J是一款先进的1.0 A双输出&#xff0c;易于使用&#xff0c;智能的手机IGBT门驱动光耦合器接口。专为支持而设计MOSFET制造商的各种电流评级&#xff0c;ACPL-339J使它更容易为系统工程师支持不同的系统额定功率使用一个硬件平台通过…

全面解析若依框架(springboot-vue前后分离--后端部分)

1、 若依框架分解 - 启动配置 前端启动 # 进入项目目录 cd ruoyi-ui# 安装依赖 npm install# 强烈建议不要用直接使用 cnpm 安装&#xff0c;会有各种诡异的 bug&#xff0c;可以通过重新指定 registry 来解决 npm 安装速度慢的问题。 npm install --registryhttps://regist…

算法刷题打卡第47天:排序数组---归并排序

排序数组 难度&#xff1a;中等 给你一个整数数组 nums&#xff0c;请你将该数组升序排列。 示例 1&#xff1a; 输入&#xff1a;nums [5,2,3,1] 输出&#xff1a;[1,2,3,5]示例 2&#xff1a; 输入&#xff1a;nums [5,1,1,2,0,0] 输出&#xff1a;[0,0,1,1,2,5]归并排…

用CSS给健身的侣朋友做一个喝水记录本

前言 事情是这样的&#xff0c;由于七八月份的晚上时不时就坐在地摊上开始了喝酒撸串的一系列放肆的长肉肉项目。 这不&#xff0c;前段时间女朋友痛下决心&#xff08;心血来潮&#xff09;地就去报了一个健身的私教班&#xff0c;按照教练给的饮食计划中&#xff0c;其中有一…

卵巢早衰与微生物群,营养治疗新进展

卵巢早衰 卵巢早衰&#xff08;premature ovarian insufficiency&#xff0c;简称POI&#xff09;在生殖系统疾病中位居首位&#xff0c;这些疾病可能会损害多个功能系统&#xff0c;降低生活质量&#xff0c;最终剥夺女性患者的生育能力。 目前的激素替代疗法不能改善受孕或降…

NR PDSCH(七) DL SPS

非动态调度&#xff0c;除了PUSCH configured grant type 1和2的传输&#xff0c;还有PDSCH SPS 传输&#xff0c;两者的流程基本类似&#xff0c;也有些小区别。在实网并没有见过配置DL SPS PDSCH传输的log&#xff0c;但还是按顺序理一遍相关内容。 RRC/MAC 先看下MAC 38.32…

文件上传,还存储在应用服务器?

一般项目开发中都会有文件、图片、视频等文件上传并能够访问的场景。要实现这样的场景&#xff0c;要么把文件存储在应用服务器上&#xff0c;要么搭建文件服务来存储。但是这两种方式也有不少的缺点&#xff0c;增加运维的成本。 因此&#xff0c;追求用户体验的项目可能会考…

Tomcat安装配置全解

&#x1f44c; 棒棒有言&#xff1a;也许我一直照着别人的方向飞&#xff0c;可是这次&#xff0c;我想要用我的方式飞翔一次&#xff01;人生&#xff0c;既要淡&#xff0c;又要有味。凡事不必太在意&#xff0c;一切随缘&#xff0c;缘深多聚聚&#xff0c;缘浅随它去。凡事…

数据库分库分表

文章目录为什么要分库分表&#xff1f;数据切分垂直切分水平切分&#xff08;每个表的结构相同&#xff09;范围拆分取模拆分&#xff08;一般为业务主键&#xff09;分库分表带来的问题数据倾斜问题热点问题事务问题聚合查询问题分页问题非分区业务查询分库分表实现或工具hash…

DSP篇--C6701功能调试系列之 UART串口测试

目录 1、原理 2、测试 调试的前期准备可以参考前面的博文&#xff1a;DSP篇--C6701功能调试系列之前期准备_nanke_yh的博客-CSDN博客 UART串口收发数据存在两种模式&#xff1a;通常的串口模式&#xff08;McBSP in Serial Port Mode&#xff09;和GPIO模式&#xff08;McBS…

哈希表及其与Java类集的关系

目录 1.哈希表的概念 2.哈希冲突 3.如何避免哈希冲突? 3.1哈希函数设计 3.2 负载因子的调节 4.解决哈希冲突 4.1闭散列 4.1.1线性探测 4.1.2二次探测 4.2开散列(哈希桶) 5.HashMap 6.HashSet 1.哈希表的概念 假设有一组数据,要让你去搜索其中的一个关键码,这种场…

JWT快速入门及所需依赖

目录 1.JWT 1.1什么是JWT 1.2JWT的构成 jwt的头部 payload signature 1.3JWT快速入门案例 2Jwt认证&#xff08;微服务&#xff09; 2.1微服务下统一权限认证 2.2应用认证 3.无状态的JWT令牌如何实现续签功能&#xff1f; 3.1不允许改变Token令牌实现续签 3.2允许改…

计算机毕业设计django基于python大学生多媒体学习系统

项目介绍 随着计算机多媒体技术的发展和网络的普及。采用当前流行的B/S模式以及3层架构的设计思想通过Python技术来开发此系统的目的是建立一个配合网络环境的大学生多媒体学习系统的平台,这样可以有效地解决数据学习系统混乱的局面。 本文首先介绍了大学生多媒体学习系统的发…