springboot从入门到精通(三十四)如何集成jwt实现token验证

章为忠学架构      2022-04-08     652

关键词:

近年来,随着前后端分离、微服务等架构的兴起,传统的cookie+session身份验证模式已经逐渐被基于Token的身份验证模式取代。接下来介绍如何在Spring Boot项目中集成JWT实现Token验证。

一、JWT入门

1.什么是JWT

JWT (Json web token)是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519)。它定义了一种紧凑的,自包含的方式,用于通信双方之间以JSON对象的形式安全传递信息。JWT使用HMAC算法或者是RSA的公私秘钥的数字签名技术,所以这些信息是可被验证和信任的。

JWT官网: ​​https://jwt.io/​

JWT(Java版)的github地址:https://github.com/jwtk/jjwt


2.JWT的结构

在使用 JWT 前,需要先了解它的组成结构。它是由以下三段信息构成的:

  • Header 头部(包含签名和/或加密算法的类型)
  • Payload 载荷 (存放有效信息)
  • Signature 签名/签证

将这三段信息文本用‘.’连接一起就构成完整的JWT字符串,也是就我们需要的Token。如下所示:

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0aW1lU3RhbXAiOjE2MzkwNDc1NTMxNjksInVzZXJSb2xlIjoiUk9MRV9BRE1JTiIsInVzZXJJZCI6ImFkbWluIn0.UFQLvaiQ1AThx9Fa4SRqNg-b9HPJ9y1TlgQB4-F3pi0

JWT的数据结构还是比较复杂的,Header,Payload,Signature中包含了很多信息,建议大家最好是能够了解。


3.JWT的请求流程

JWT的请求流程也特别简单,首先使用账号登录获取Token,然后后面的各种请求,都带上这个Token即可。具体流程如下:

1. 客户端发起登录请求,传入账号密码;

2. 服务端使用私钥创建一个Token;

3. 服务器返回Token给客户端;

4. 客户端向服务端发送请求,在请求头中该Token;

5. 服务器验证该Token;

6. 返回结果。

SpringBoot从入门到精通(三十四)如何集成JWT实现Token验证_示例代码


二、Spring Boot 如何集成JWT

JWT提供了基于Java组件:java-jwt帮助我们在Spring Boot项目中快速集成JWT,接下来进行SpringBoot和JWT的集成。

1.引入JWT依赖

创建普通的Spring Boot项目,修改项目中的pom.xml文件,引入JWT等依赖。示例代码如下:

<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.10.3</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

2.创建&验证Token

创建通用的处理类TokenUtil,负责创建和验证Token。示例代码如下:

@Component
public class TokenUtil
@Value("$token.secretKey")
private String secretKey;

/**
* 加密token.
*/
public String getToken(String userId, String userRole)
//这个是放到负载payLoad 里面,魔法值可以使用常量类进行封装.
String token = JWT
.create()
.withClaim("userId" ,userId)
.withClaim("userRole", userRole)
.withClaim("timeStamp", System.currentTimeMillis())
.sign(Algorithm.HMAC256(secretKey));
return token;


/**
* 解析token.
*
* "userId": "weizhong",
* "userRole": "ROLE_ADMIN",
* "timeStamp": "134143214"
*
*/
public Map<String, String> parseToken(String token)
HashMap<String, String> map = new HashMap<String, String>();
DecodedJWT decodedjwt = JWT.require(Algorithm.HMAC256(secretKey))
.build().verify(token);
Claim userId = decodedjwt.getClaim("userId");
Claim userRole = decodedjwt.getClaim("userRole");
Claim timeStamp = decodedjwt.getClaim("timeStamp");
map.put("userId", userId.asString());
map.put("userRole", userRole.asString());
map.put("timeStamp", timeStamp.asLong().toString());
return map;

3.创建拦截器,验证Token

创建一个拦截器AuthHandlerInterceptor,负责拦截所有Http请求,验证Token是否有效。示例代码如下:

@Slf4j
@Component
public class AuthHandlerInterceptor implements HandlerInterceptor
@Autowired
TokenUtil tokenUtil;

@Value("$token.refreshTime")
private Long refreshTime;
@Value("$token.expiresTime")
private Long expiresTime;
/**
* 权限认证的拦截操作.
*/
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) throws Exception
if (!(object instanceof HandlerMethod))
return true;

//为空就返回错误
String token = httpServletRequest.getHeader("token");
if (null == token || "".equals(token.trim()))
return false;

log.info("==============token:" + token);
Map<String, String> map = tokenUtil.parseToken(token);
String userId = map.get("userId");
String userRole = map.get("userRole");
long timeOfUse = System.currentTimeMillis() - Long.parseLong(map.get("timeStamp"));
//1.判断 token 是否过期
if (timeOfUse < refreshTime)
log.info("token验证成功");
return true;

//超过token刷新时间,刷新 token
else if (timeOfUse >= refreshTime && timeOfUse < expiresTime)
httpServletResponse.setHeader("token",tokenUtil.getToken(userId,userRole));
log.info("token刷新成功");
return true;

//token过期就返回 token 无效.
else
throw new TokenAuthExpiredException();


拦截器创建之后,需要将拦截器注册到Spring Boot中。这和其他的拦截器注册是一样的。示例代码如下:

@Configuration
public class AuthWebMvcConfigurer implements WebMvcConfigurer

@Autowired
AuthHandlerInterceptor authHandlerInterceptor;

/**
* 给除了 /login 的接口都配置拦截器,拦截转向到 authHandlerInterceptor
*/
@Override
public void addInterceptors(InterceptorRegistry registry)
registry.addInterceptor(authHandlerInterceptor)
.addPathPatterns("/**")
.excludePathPatterns("/login");


4.创建控制器

创建TokenTestController控制器,处理HTTP请求。示例代码如下:

@RestController
public class TokenTestController
@Autowired
TokenUtil tokenUtil;

@PostMapping("/login")
public String login(@RequestBody LoginUser user)
// 先验证用户的账号密码,账号密码验证通过之后,生成Token
String role = "ROLE_ADMIN";
String token = tokenUtil.getToken(user.username,role);
return token;


@PostMapping("/testToken")
public String testToken(HttpServletRequest request)
String token = request.getHeader("token");
tokenUtil.parseToken(token);
return "请求成功";


5.测试验证

集成JWT成功之后,接下来验证Token是否成功,启动项目。在Postman中调用相关接口,验证功能是否正常。

首先,调用​​http://localhost:8080/testToken​​,获取token

SpringBoot从入门到精通(三十四)如何集成JWT实现Token验证_jwt_02


然后,调用​​http://localhost:8080/testToken​​ 验证token是否有效。

SpringBoot从入门到精通(三十四)如何集成JWT实现Token验证_jwt_03


最后

以上,我们就把Spring Boot集成JWT实现Token验证介绍完了。身份验证是Web开发中非常基础的功能,后面还会介绍授权及权限管理等内容。


dubbo从入门到精通与springboot集成的三种方式(十一)(代码片段)

1 方式一(注解方式)导入dubbo-starter,在application.properties配置属性,使用@Service【暴露服务】使用Reference【引用服务】新版本的dubbo 是@DubboService 和@DubboReference然后在启动类上面 标 @EnableDubbo 开启基于注解的du... 查看详情

springboot入门到精通-springboot入门(代码片段)

SpringBoot入门到精通系列SpringBoot入门到精通-Spring的注解编程(一)SpringBoot入门到精通-SpringBoot入门(二)SpringBoot入门到精通-Spring的基本使用(三)SpringBoot入门到精通-SpringBoot集成SSM(四)前言经过上面的学习,我们已经掌握的Spring的注... 查看详情

springboot入门到精通-springboot自定义starter(代码片段)

定义自己的starterSpringBoot入门到精通-Spring的注解编程(一)SpringBoot入门到精通-SpringBoot入门(二)SpringBoot入门到精通-Spring的基本使用(三)SpringBoot入门到精通-SpringBoot集成SSM(四)SpringBoot入门到精通-SpringBoot自动配置原理(五)SpringBoot入门... 查看详情

springboot入门到精通-spring的注解编程(代码片段)

SpringBoot入门到精通系列SpringBoot入门到精通-Spring的注解编程(一)SpringBoot入门到精通-SpringBoot入门(二)SpringBoot入门到精通-Spring的基本使用(三)SpringBoot入门到精通-SpringBoot集成SSM(四)前言SpringBoot并不是一个新技术了,但是我发现... 查看详情

springboot入门到精通-spring的基本使用(代码片段)

SpringBoot入门到精通系列SpringBoot入门到精通-Spring的注解编程(一)SpringBoot入门到精通-SpringBoot入门(二)SpringBoot入门到精通-Spring的基本使用(三)SpringBoot入门到精通-SpringBoot集成SSM(四)前言上一篇文章我们讲的是SpringBoot的入门程序,... 查看详情

springboot从入门到精通-项目搭建

参考技术ASpringBoot极大的简化了java项目的开发,在之前如果想要开发一个java项目,需要安装tomcat或者其他容器插件。但是SpringBoot内部已经集成了tomcat,因此项目的启动异常的方便。而且SpringBoot的开发中有很多默认的配置,帮助... 查看详情

mysql从入门到精通50讲(三十五)-执行计划详解

执行计划输出各列的含义详解如果我们想查看某个查询的执行计划,可以在具体的查询语句前面加一个EXPLAIN或DESC或DESCRIBE均可,就像下面这样。输出的内容就是执行计划。除了将上述三个关键字任意一个加在SELECT语句前,DELETE... 查看详情

mysql从入门到精通50讲(三十五)-执行计划详解

执行计划输出各列的含义详解如果我们想查看某个查询的执行计划,可以在具体的查询语句前面加一个EXPLAIN或DESC或DESCRIBE均可,就像下面这样。输出的内容就是执行计划。除了将上述三个关键字任意一个加在SELECT语句前,DELETE... 查看详情

springboot入门到精通-springboot自动配置原理(代码片段)

SpringBoot源码解析SpringBoot入门到精通-Spring的注解编程(一)SpringBoot入门到精通-SpringBoot入门(二)SpringBoot入门到精通-Spring的基本使用(三)SpringBoot入门到精通-SpringBoot集成SSM(四)SpringBoot入门到精通-SpringBoot自动配置原理(五)SpringBoot入门... 查看详情

java基础教程从入门到精通,社招面试心得

一、SpringBoot相关(1)SpringBoot面试专题什么是SpringBoot?SpringBoot有哪些优点?什么是JavaConfig?如何重新加载SpringBoot上的更改,而无需重新启动服务器?SpringBoot中的监视器是什么?如何在SpringBoot中... 查看详情

springboot从入门到精通

这一节我们一起用springboot开发一个应用程序,应用程序里的核心概念是玩家获取英雄列表上的英雄信息。1、定义实体模型:代码如下:packagecom.dota.herolist.entity;importjavax.persistence.Entity;importjavax.persistence.GeneratedValue;importjavax.persist... 查看详情

flask框架从入门到精通之蓝图(二十四)(代码片段)

知识点:1、蓝图一、概况从前面的知识点能看出来,我们所有的视图函数都写在了一个文件当中,当我们的业务越来复杂的时候。视图函数也会变得越来越多,导致阅读不方便,维护起来困难等难题。比如下... 查看详情

mysql从入门到精通50讲(三十二)-scylladb生产环境集群搭建

服务器规划&准备工作01环境介绍名称详情服务器京东公有云ECS:32C/128G/8T(存储优化IO型本地NVMeSSD直通盘)×5台操作系统版本CentOSLinuxrelease7.4.1708(Core)操作系统内核版本3.10.0-693.el7.x86_64ScyllaDB版本4.4.4因为ScyllaDB集群的数据最终会... 查看详情

mysql从入门到精通50讲(三十二)-scylladb生产环境集群搭建

服务器规划&准备工作01环境介绍名称详情服务器京东公有云ECS:32C/128G/8T(存储优化IO型本地NVMeSSD直通盘)×5台操作系统版本CentOSLinuxrelease7.4.1708(Core)操作系统内核版本3.10.0-693.el7.x86_64ScyllaDB版本4.4.4因为ScyllaDB集群的数据最终会... 查看详情

嵌入式linux从入门到精通之第十四节:linuxio控制技术

目录设备控制概述操作设备文件函数监听文件描述符示例设备控制概述对于硬件设备,Linux采用了与裸机完全不同的机制进行管理。Linux下的所有硬件(IO、键盘、鼠标等)均是以文件的形式进行统一管理的,每个设备在/dev/目录下... 查看详情

flink从入门到精通100篇(二十四)-对flinksqlclient源码做深度解析(代码片段)

前言本文基于Flink1.12-SNAPSHOT,使用sqlclient命令行提交insert语句进行整个流程的分析。sql-client.sh embedded --update "INSERT INTO user_log_sink2 SELECT * FROM user_log"Initializethe 查看详情

springboot从入门到精通

...始第三节之前,先补充一下第二节里出现的小问题,就是springboot的application.properties,我在文件中添加了server.port=9090这个参数,但是启动项目后并未生效,检查了一下原因,是因为未读取到该文件,这里可以通过buildpath添加source... 查看详情

springboot从入门到精通

 springboot到底有什么好处?有什么优势?这个先不用看,我们只要知道它有很多优势,现在要做的事只有一件,那就是撸代码!撸完就知道有多少料!首先,在案例中,我们会构建一个英雄列表应用。操作如下:1、初始化一... 查看详情