JWT详解
1.前言
定义:JSON Web Token(缩写 JWT)是目前最流行的跨域认证解决方案
由于HTTP协议是无状态的,这意味着如果我们想判定一个接口是否被认证后访问,就需要借助cookie或者session会话机制进行判定,但是由于现在的系统架构大部分都不止一台服务器,此时又要借助数据库或者全局缓存 做存储,这种方案显然受限太多。
那么我们可不可以让认证令牌的发布者自己去识别这个令牌是不是我曾经发布的令牌呢(JWT核心思想),这是JWT最大的优点也是最大的缺点,优点是简单快捷、不需要依赖任何第三方操作就能实现身份认证,缺点就是对于任何拥有用户发布令牌的请求都会认证通过。
2.JWT的数据结构
正常的JWT数据结构应该如下

它是一个很长的字符串,中间用点(.)分隔成三个部分
JWT的三个部分依次: Header - 头部 、Payload - 负载 、Signature(签名)
即:Header.Payload.Signature
2.1 Header
Header 部分是一个 JSON 对象,描述 JWT 的元数据,通常是下面的样子。
{
"alg": "HS256",
"typ": "JWT"
}
alg属性表示签名的算法(algorithm),默认是 HMAC SHA256(写成 HS256);typ属性表示这个令牌(token)的类型(type),JWT 令牌统一写为JWT
2.2 Payload
Payload 部分也是一个 JSON 对象,用来存放实际需要传递的数据。JWT 规定了7个官方字段,供选用。
iss (issuer):签发人
exp (expiration time):过期时间
sub (subject):主题
aud (audience):受众
nbf (Not Before):生效时间
iat (Issued At):签发时间
jti (JWT ID):编号
除了官方字段,你还可以在这个部分定义私有字段
{
"sub": "1234567890",
"name": "John Doe",
"age": "19"
}
注意:JWT默认是明文展示,任何人都可以读取到,所以此处不要放私密信息
这个 JSON 对象也要使用 Base64URL 算法转成字符串。
2.3 Signature
Signature 部分是对前两部分的签名,防止数据篡改。
首先,需要指定一个密钥(secret)。这个密钥只有服务器才知道,不能泄露给用户。然后,使用 Header 里面指定的签名算法(默认是 HMAC SHA256),按照下面的公式产生签名。
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
算出签名以后,把 Header、Payload、Signature 三个部分拼成一个字符串,每个部分之间用"点"(.)分隔,就可以返回给用户。
2.4 Base64URL
前面提到,Header 和 Payload 串型化的算法是 Base64URL。这个算法跟 Base64 算法基本类似,但有一些小的不同。
JWT 作为一个令牌(token),有些场合可能会放到 URL(比如 api.example.com/?token=xxx)。Base64 有三个字符+、/和=,在 URL 里面有特殊含义,所以要被替换掉:=被省略、+替换成-,/替换成_ 。这就是 Base64URL 算法
3. JWT的实现
Maven依赖
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.5.0</version>
</dependency>
JWT签名发布和验证代码
public class TokenUtil {
//Token的过期时间
private static final long EXPIRE_TIME = 30 * 60 * 1000;
//Token的私钥
private static final String TOKEN_SECRET = "jytoken_secret";
/**
* 生成签名,30分钟过期
* @param **userInfo** 用户信息 用户姓名
* @param **other** 用户其他信息 用户id
* @return
*/
public static String sign(String userInfo, String other) {
try {
// 设置过期时间
Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
//私钥和加密算法
Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);
// 设置头部信息
Map<String, Object> header = new HashMap<>(2);
header.put("Type", "Jwt");
header.put("alg", "HS256");
// 返回token字符串
return JWT.create()
.withHeader(header)
.withClaim("userInfo", userInfo)
.withClaim("other", other)
.withExpiresAt(date)
.sign(algorithm);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 生成签名,30分钟过期
* @param **userInfo** 用户信息 用户姓名
* @param **other** 用户其他信息 用户id
* @return
*/
public static String sign(String userInfo, String other,long expire) {
try {
// 设置过期时间
Date date = new Date(System.currentTimeMillis() + expire);
//私钥和加密算法
Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);
// 设置头部信息
Map<String, Object> header = new HashMap<>(2);
header.put("Type", "Jwt");
header.put("alg", "HS256");
// 返回token字符串
return JWT.create()
.withHeader(header)
.withClaim("userInfo", userInfo)
.withClaim("other", other)
.withExpiresAt(date)
.sign(algorithm);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 检验token是否正确
* @param **token**
* @return
*/
public static boolean verify(String token){
try {
Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);
JWTVerifier verifier = JWT.require(algorithm).build();
verifier.verify(token);//未验证通过会抛出异常
return true;
} catch (Exception e){
return false;
}
}
/**
* 从token中获取info信息
* @param **token**
* @return
*/
public static String getUserName(String token,String info){
try {
DecodedJWT jwt = JWT.decode(token);
return jwt.getClaim(info).asString();
} catch (JWTDecodeException e){
e.printStackTrace();
}
return null;
}
}
拦截器配置无需认证的请求
@Configuration
public class InterceptorConfig extends WebMvcConfigurationSupport {
@Autowired
private TokenHandler tokenHandler;
@Override
public void addInterceptors(InterceptorRegistry registry) {
List<String> excludePath = new ArrayList<>();
String checkLogin = "/pushlogin/checkIsCanLogin";
String login = "/pushlogin/login";
String getVerifyCode = "/common/send";
String verfifyMethod = "/common/validationCode";
excludePath.add(checkLogin);
excludePath.add(login);
excludePath.add(getVerifyCode);
excludePath.add(verfifyMethod);
registry.addInterceptor(tokenHandler).excludePathPatterns(excludePath);
}
}
Token统一拦截器代码
@Component
@Slf4j
public class TokenHandler implements HandlerInterceptor{
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String token = request.getHeader("Authentication");
if (token != null){
boolean result = TokenUtil.verify(token);
if(result){
log.info("通过拦截器");
return true;
}
}
log.info("认证失败");
return false;
}
}
用户登录时验证用户信息后,返回Token信息
@Override
public UserDTO selectIsExistUserInfo(String phone) {
//TODO 伪代码 验证用户信息
UserDTO info = 查询用户信息
if (info != null) {
String token = TokenUtil.sign(info.getUsername(), info.getUserId(), 6 * 60 * 60 * 1000);
info.setToken(token);
}
return info;
}
JWT详解的更多相关文章
- SpringSceurity(6)---JWT详解
SpringSceurity(6)---JWT详解 在JWT之前我们在做用户认证的时候,基本上会考虑session 和 token,所以在讲jwt之前,我们先来回顾下这个两个 一.传统的session ...
- 授权认证登录之 Cookie、Session、Token、JWT 详解
一.先了解几个基础概念 什么是认证(Authentication) 通俗地讲就是验证当前用户的身份. 互联网中的认证: 用户名密码登录 邮箱发送登录链接 手机号接收验证码 只要你能收到邮箱/验证码,就 ...
- Json Web Token(JWT)详解
什么是Json Web Token Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的 ...
- 全栈项目|小书架|服务器开发-JWT 详解
JWT 官方简介:Introduction to JSON Web Tokens 文章基本是官网内容的翻译,英文不错的同学可点击上面的链接直接看英文文档. 什么是 JWT JWT全称是JSON Web ...
- JWT详解-(JSON Web Token教程)
JSON Web Token(缩写 JWT)是目前最流行的跨域认证解决方案,本文介绍它的原理和用法. 一.跨域认证的问题 互联网服务离不开用户认证.一般流程是下面这样. 1.用户向服务器发送用户名和密 ...
- JWT(Json web token)认证详解
JWT(Json web token)认证详解 什么是JWT Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该to ...
- IdentityServer4实战 - JWT Token Issuer 详解
原文:IdentityServer4实战 - JWT Token Issuer 详解 一.前言 本文为系列补坑之作,拖了许久决定先把坑填完. 下文演示所用代码采用的 IdentityServer4 版 ...
- 前后端分离,简单JWT登录详解
前后端分离,简单JWT登录详解 目录 前后端分离,简单JWT登录详解 JWT登录流程 1. 用户认证处理 2. 前端登录 3. 前端请求处理 4. 后端请求处理 5. 前端页面跳转处理 6. 退出登录 ...
- JWT基础概念详解
JWT基础概念详解 JWT介绍 之前我们文章讲过分布式session如何存储,其中就讲到过Token.JWT.首先,我们来回顾一下使用Token进行身份认证. 客户端发送登录请求到服务器 服务器在用户 ...
随机推荐
- C++ 洛谷 2014 选课 from_树形DP
洛谷 2014 选课 没学树形DP的,看一下. 首先要学会多叉树转二叉树. 树有很多种,二叉树是一种人人喜欢的数据结构,简单而且规则.但一般来说,树形动规的题目很少出现二叉树,因此将多叉树转成二叉树就 ...
- java虚拟机-程序计数器PC Register
什么是程序计数器? 程序计数器是一块 较小 的内存空间,它可以看做是当前线程所执行的字节码的 行号指示器 :在虚拟机的概念模型里(仅仅是概念模型,各种虚拟机可能会通过一些更高效的方式去实现),字节码解 ...
- input的值为浅淡样式(点击值消失)
<input type="text" id="leftSearchValue" value="" placeholder=" ...
- Java设计模式学习笔记(一) 设计模式概述
前言 大约在一年前学习过一段时间的设计模式,但是当时自己的学习方式比较低效,也没有深刻的去理解.运用所学的知识. 所以现在准备系统的再重新学习一遍,写一个关于设计模式的系列博客. 废话不多说,正文开始 ...
- python笔记(2)--字符串
一.字符串 字符串是不可变序列,具有序列的公共操作方法,具体操作见python笔记(1)--序列(列表 元组 range) 1.创建字符串 单引号:'Hello , I am Logan ! ' 双引 ...
- C语言指针专题——如何理解指针
本文为原创,欢迎转发! 最近在研读C primer plus 5版中文版,老外写的,还是很经典的,推荐给读者们,有需要的朋友可以在这里购买:C primer plus 5版中文版 指针,传说中是C语言 ...
- 微信小程序开发--API界面交互
一.wx:showActionSheet(上拉菜单) 属性 类型 默认值 必填 说明 itemList Array.<string> 是 按钮的文字数组,数组长度最大为 6 itemC ...
- Prim算法与Kruskal(没有代码)
两个最小生成树算法, 都有一个共同的思想: 这棵树是一点一点长大的; 并且每次生长, 都是贪心的. 不同之处是: Kruscal算法是以边为中心的, 每次找最小的并且有用的边添加到树上; Prim算法 ...
- 2019.6.16完成classstack任务
最终信息 4 ShineEternal 任务完成,账号已注销 120 149 80.537%
- [WPF自定义控件库]自定义Expander
1. 前言 上一篇文章介绍了使用Resizer实现Expander简单的动画效果,运行效果也还好,不过只有展开/折叠而缺少了淡入/淡出的动画(毕竟Resizer模仿Expander只是附带的功能).这 ...