什么是JWT?

Json web token (JWT),是为了在网络应用环境间传递声明而执行的一种基于 JSON 的开放标准((RFC 7519),该 token 被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT 的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。

为什么需要JWT?

当我们开发前后端分离项目时,要求我们对用户会话状态要进行一个无状态处理,那我们知道普通的web项目用于管理用户会话的往往是 session,用户每次用服务器认证成功后,服务器都会发送一个 sessionid 给用户,session 是保存在服务端的,服务器通过 session 分辨用户,进行权限认证等一系列操作。每次请求完后,都会在 响应头中返回 sessionid 给浏览器,浏览器会将 sessionid 存储在 cookie 中,以后的每次请求都会在请求头中带上这个 sessionid 信息,服务器就会根据这个 sessionid 作为索引获取到具体的 session。

那上面讲述的场景就会出现一个痛点,当我们前后端分离后,我们的前端项目和后端项目分开部署,甚至会用到 nginx 来代理转发,也就是说前后端分离在应用解耦后增加了部署的复杂性。通常用户一次请求就要转发多次。如果用 session 每次携带 sessionid 到服务器,服务器还要查询用户信息。同时如果用户很多。这些信息存储在服务器内存中,给服务器增加负担。还有就是 CSRF(跨站伪造请求攻击)攻击,session 是基于 cookie 进行用户识别的, cookie 如果被截获,用户就会很容易受到跨站请求伪造的攻击。还有就是 sessionid 就是一个特征值,表达的信息不够丰富。不容易扩展。而且如果你后端应用是多节点部署。那么就需要实现 session 共享机制。不方便集群应用。

JWT的应用场景

JWT 就是上述痛点的解决方案之一,客户端在请求服务端进行登录操作时,服务端验证用户的账号和密码,验证成功后生成 token 返回给客户端,之后浏览器的每一次操作都会在请求头中带上这个 token,服务器会验证该 token 信息,验证成功后才会返回资源给浏览器。

JWT 的开销非常小,可以轻松在不同的域名中传递,所以在单点登录(SSO)中用到比较广泛,信息交换在通信的双方之间使用JWT对数据进行编码是一种非常安全的方式,由于它的信息是经过签名的,可以确保发送者发送的信息是没有经过伪造的。

整合JWT

1、引入 JWT 依赖

<!-- 引入jwt -->
<dependency><groupId>com.auth0</groupId><artifactId>java-jwt</artifactId><version>3.8.2</version>
</dependency>

2、JWT 工具类

  • 工具类中包含:创建 token,验证 token,获取用户 id 等
package com.asurplus.common.jwt;import cn.hutool.core.collection.CollectionUtil;
import com.asurplus.common.utils.ResponseResult;
import com.asurplus.common.utils.SpringContextUtils;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.auth0.jwt.interfaces.JWTVerifier;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;/*** Jwt工具类,生成JWT和认证** @author dongk* @date 2021-02-05 11:10:08*/
@Slf4j
public class JwtUtil {/*** 密钥*/private static final String SECRET = "asurplus_secret";/*** 过期时间(单位:秒)**/private static final long EXPIRATION = 3600L;/*** 生成用户token,设置token超时时间** @param userId* @param password* @return*/public static String createToken(Integer userId, String account, String password) {Map<String, Object> map = new HashMap<>();map.put("alg", "HS256");map.put("typ", "JWT");String token = JWT.create()// 添加头部.withHeader(map)// 放入用户的id.withAudience(String.valueOf(userId))// 可以将基本信息放到claims中.withClaim("account", account).withClaim("password", password)// 超时设置,设置过期的日期.withExpiresAt(new Date(System.currentTimeMillis() + EXPIRATION * 1000))// 签发时间.withIssuedAt(new Date())// SECRET加密.sign(Algorithm.HMAC256(SECRET));return token;}/*** 获取用户id*/public static Integer getUserId() {HttpServletRequest request = SpringContextUtils.getHttpServletRequest();// 从请求头部中获取token信息String token = request.getHeader("Authorization");if (StringUtils.isBlank(token)) {return null;}try {Algorithm algorithm = Algorithm.HMAC256(SECRET);JWTVerifier verifier = JWT.require(algorithm).build();DecodedJWT jwt = verifier.verify(token);if (null != jwt) {// 拿到我们放置在token中的信息List<String> audience = jwt.getAudience();if (CollectionUtil.isNotEmpty(audience)) {return Integer.parseInt(audience.get(0));}}} catch (IllegalArgumentException e) {e.printStackTrace();} catch (JWTVerificationException e) {e.printStackTrace();}return null;}/*** 校验token并解析token*/public static ResponseResult verity() {HttpServletRequest request = SpringContextUtils.getHttpServletRequest();// 从请求头部中获取token信息String token = request.getHeader("Authorization");if (StringUtils.isBlank(token)) {return ResponseResult.error(401, "用户信息已过期,请重新登录");}try {Algorithm algorithm = Algorithm.HMAC256(SECRET);JWTVerifier verifier = JWT.require(algorithm).build();DecodedJWT jwt = verifier.verify(token);if (null != jwt) {// 拿到我们放置在token中的信息List<String> audience = jwt.getAudience();if (CollectionUtil.isNotEmpty(audience)) {return ResponseResult.success("认证成功", audience.get(0));}}} catch (IllegalArgumentException e) {e.printStackTrace();} catch (JWTVerificationException e) {e.printStackTrace();}return ResponseResult.error(401, "用户信息已过期,请重新登录");}
}

我们可以看出 token 的创建用到了如下参数:

  • 算法:HS256
  • 类型:jwt
  • withAudience:向有效负载添加特定的受众(“aud”)声明,我们可以在这里放入一些用户的信息,例如:用户 id
  • withClaim:添加自定义索赔值,我们使用用户的账户和密码进行一起加密生成 jwt
  • withExpiresAt:超时时间设置,超时 token 将失效
  • withIssuedAt:签发时间,一般设置为当前时间
  • sign:签名,我们可以自定义签名和算法

JWT 的验证:

  • 首先我们先要获取 HttpServletRequest 请求对象,工具类放在下面了
  • 从请求头中获取 token 信息,根据 key(Authorization)获取 value 值
  • 然后使用签名进行算法加密得到 jwt 的验证对象,JWTVerifier.verify(token) 用来验证 token 的正确性
  • 我们还可以从验证得到的 DecodedJWT 对象中获取我们创建 token 的时候放入的信息,例如:用户 id

获取 HttpServletRequest 对象工具类

package com.asurplus.common.utils;import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;import javax.servlet.http.HttpServletRequest;/*** SpringContext工具类** @Author Lizhou*/
@Component
public class SpringContextUtils implements ApplicationContextAware {/*** 上下文对象实例*/private static ApplicationContext applicationContext;@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {SpringContextUtils.applicationContext = applicationContext;}/*** 获取applicationContext** @return*/public static ApplicationContext getApplicationContext() {return applicationContext;}/*** 获取HttpServletRequest*/public static HttpServletRequest getHttpServletRequest() {return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();}public static String getDomain() {HttpServletRequest request = getHttpServletRequest();StringBuffer url = request.getRequestURL();return url.delete(url.length() - request.getRequestURI().length(), url.length()).toString();}public static String getOrigin() {HttpServletRequest request = getHttpServletRequest();return request.getHeader("Origin");}
}

自定义 JSON 对象工具类

package com.asurplus.common.utils;import com.asurplus.common.enums.BaseEnums;
import com.asurplus.common.enums.StatusEnums;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;import java.io.Serializable;/*** 单例模式返回接口相应数据** @Author Lizhou*/
@Data
public class ResponseResult implements Serializable {@ApiModelProperty(value = "状态码")private Integer code;@ApiModelProperty(value = "提示信息")private String msg;@ApiModelProperty(value = "返回数据")private Object data;private static ResponseResult resultData(Integer code, String msg, Object data) {ResponseResult res = new ResponseResult();res.setCode(code);res.setMsg(msg);res.setData(data);return res;}/*** 成功*/public static ResponseResult success() {return resultData(200, "操作成功", null);}/*** 成功*/public static ResponseResult success(String msg) {return resultData(200, msg, null);}/*** 成功*/public static ResponseResult success(Object data) {return resultData(200, "操作成功", data);}/*** 成功*/public static ResponseResult success(String msg, Object data) {return resultData(200, msg, data);}/*** 失败*/public static ResponseResult error() {return resultData(500, "操作失败", null);}/*** 失败*/public static ResponseResult error(Integer code) {return resultData(code, null, null);}/*** 失败*/public static ResponseResult error(Integer code, String msg) {return resultData(code, msg, null);}/*** 失败*/public static ResponseResult error(String msg) {return resultData(500, msg, null);}/*** 失败*/public static ResponseResult error(Object data) {return resultData(500, "操作失败", data);}/*** 失败*/public static ResponseResult error(Integer code, String msg, Object data) {return resultData(code, msg, data);}/*** 失败*/public static ResponseResult error(BaseEnums enums) {return resultData(enums.getCode(), enums.getMsg(), null);}
}

至此,我们在 SpringBoot 中整合 JWT 实现 Token 验证已经完成。

如您在阅读中发现不足,欢迎留言!!!

【SpringBoot】44、SpringBoot中整合JWT实现Token验证(整合篇)相关推荐

  1. SpringBoot 整合 JWT 实现 Token 验证

    前言 在Spring Security整合oauth2实现认证token也不满足实际生产需求的时候,可以整合Jwt实现token认证,完全手写获取token,认证token的方法. Maven依赖包 ...

  2. SpringBoot(9)整合JWT实现Token验证

    一.什么是JWT Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).定义了一种简洁的,自包含的方法用于通信双方之间以J ...

  3. json web token没有哪个成分_SpringBoot 2.1.4集成JWT实现token验证

    SpringBoot 2.1.4集成JWT实现token验证

  4. VUE+SpringBoot+JWT实现token验证,SSO单点登录

    Session的产生: 在说session是啥之前,我们先来说说为什么会出现session会话,它出现的机理是什么?我们知道,我们用浏览器打开一个网页,用到的是HTTP协议,htpp协议是无状态的,什 ...

  5. SpringBoot集成JWT实现token验证

    Jwt全称是:json web token,以JSON对象的形式安全的传递信息.它将用户信息加密到token里,服务器不保存任何用户信息.服务器通过使用保存的密钥验证token的正确性,只要正确即通过 ...

  6. SpringSecurity - 整合JWT使用 Token 认证授权

    一.SpringSecurity 前面讲解了SpringSecurity的动态认证和动态权限角色,我们都知道在现在大多都是微服务前后端分离的模式开发,前面讲的还是基于Session的,本篇我们整合JW ...

  7. jwt token 附加用户信息_SpringBoot+JWT实现token验证并将用户信息存储到@注解内

    springboot集成jwt实现token验证 1.引入jwt依赖 io.jsonwebtoken jjwt 0.9.0 com.auth0 java-jwt 3.9.0 2.自定义两个注解 /** ...

  8. Spring Boot+Spring Security+JWT 实现token验证

    Spring Boot+Spring Security+JWT 实现token验证 什么是JWT? JWT的工作流程 JWT的主要应用场景 JWT的结构 SpringBoot+Spring Secur ...

  9. 在SPA应用中利用JWT进行身份验证

    版权声明:本文为博主chszs的原创文章,未经博主允许不得转载. https://blog.csdn.net/chszs/article/details/79639919 在SPA应用中利用JWT进行 ...

最新文章

  1. WPF窗口长时间无人操作鼠标自动隐藏
  2. ftrace跟踪内核_ftrace、kpatch、systemtap的基本原理、联系和区别
  3. 好技术领导和差技术领导区别在哪里
  4. 2.HTML基本格式
  5. Gentoo 安装日记 06 (格式化和挂载系统)
  6. 使用charles 抓取手机上的操作
  7. Eyoucms代理授权统计插件源码
  8. 手机端页面自适应解决方案-rem布局
  9. 【MFC 学习笔记】CheckListBox
  10. php 正则忽略空白,(PHP)正则表达式-忽略空白
  11. 算法篇----求两数的最大公约数和最小公倍数
  12. 武昌职业学院与湖北美和易思教育科技有限公司校企签约揭牌仪式隆重举行
  13. 机器学习/深度学习算法学习心得
  14. 在MyEclipse中,如何使用Git将项目上传到G码云仓库
  15. 经济学实证论文写作经验分享
  16. eMTC是什么技术?
  17. JAVA-获取无限循环小数的循环节
  18. Google DFP广告管理系统简介:开始与您的网站进行广告集成
  19. 微x模块怎么导入主题_WESHOP | 基于微服务的小程序商城系统
  20. ubuntu18.04鼠标可以移动但是无法点击解决方法

热门文章

  1. 读取地磁指数Ap和太阳活动指数F107程序
  2. 无人机飞控 ardupilot-4.0.7 版本源码总体框架
  3. TensorFlow Lite简介
  4. android ddms工具,请问Android Studio中怎么使用DDMS工具
  5. 创新案例 | Web3典范BrainTrust如何打造DAO增长飞轮3年扩张50倍
  6. Mac 重装Safari
  7. Java网络编程的小结--多用户即时通信系统
  8. 计算机软考等级取消了吗,软考是计算机等级考试吗
  9. fps游戏枪口无后座的原理和实现
  10. JS中的变量提升总结