JWT(Json Wen Token)原理剖析
JWT(即json web token),大家先看下面这张图
大家可以观察到,jwt String就是生成后的jwt字符集,其中有两个 "."(注意:jwt校验会对"."个数校验,多或少都会校验失败),被"."分割的就是jwt的三个构成部分,即:header、payload、sign。
接下来,给大家讲下jwt的生成规则和校验规则
JWT生成规则:
1、设置加密方式、claims信息(即payload)和signingkey
2、设置加密方式为header,并进行base编码
3、设置claims信息为payload,并进行base64编码
4、对header和payload用"."拼接成jwt,,使用signingkey按照加密方式进行加密,生成sign
5、对Jwt和sign用"."生成最终的jwt
JWT校验规则:
1、设置jwt和signingkey
2、按"."对jwt分成三部分,即:header、payload、sign
3、取第一部分进行base64解码,获取加密方式
4、取第二部分进行base64解码,获取业务参数,即payload
5、使用加密方式和signingkey创建校验器,对header+payload进行加密,并与sign(即第三部分)进行对比
6、取出payload的有效期进行校验,是否过期
7、通过校验,返回claims信息
附:
1、进行base64编码时,会判断是否为android客户端,使用base64的库不一样,这点可以自行看源码。
2、jwt会对生成的base64字符集的特殊符号进行转换,"-"换为"+",“_”换位"/",去掉尾部"="
3、jwt校验时,会判断是否有且只有两个".",否则校验失败
原理总结:
1、三部分里的header和payload是独立的,无须signingkey,只需base64解码即可看到payload的信息,所以千万不要在payload里放敏感信息
2、如果是使用jwt作为登录态校验,建议使用对称加密,因为非对称解密效率相对较慢,较多请求下会影响性能
3、因jwt是无状态的,之前见很多同学使用redis进行存储,我不是很明白,这岂不是违反了jwt当初的设计原则
4、保证密钥不要泄露,否则jwt可以被伪造
5、必要情况下,建议使用https
另附上个人的代码供大家参考
package com.yhc.demo.plugin; import java.io.UnsupportedEncodingException;
import java.util.Date; import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration; import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.SignatureException;
import io.jsonwebtoken.UnsupportedJwtException; /**
* JwtToken工具类
*/
@Configuration
public class JwtService { private static final Logger log = LoggerFactory.getLogger(JwtService.class); @Value("${jwt.secret:123456}")
private String secret;
@Value("${jwt.expiration:60}")
private Long expiration; /**
* 生成token
*
* @param username
* @return token
*/
public String generateToken(String username) { Claims claims = Jwts.claims();
claims.setIssuer(username); // jwt发行人
claims.setIssuedAt(new Date()); // jwt生成时间
claims.setExpiration(getExp()); // jwt过期时间
claims.setSubject("auth"); // jwt主题
claims.setAudience("yhc"); // jwt接受方
claims.setId("uuid"); // jwt唯一身份标识
claims.setNotBefore(new Date()); // jwt在此之前不可用 return generateToken(claims);
} /**
* 刷新token
*
* @param old token
* @return new token
*/
public String refreshToken(String token) {
Claims claims = validToken(token);
if (claims == null) {
return null;
}
claims.setIssuedAt(new Date());
claims.setExpiration(getExp());
return generateToken(claims);
} /**
* 根据token获取发行人
*
* @param token
* @return issuer
*/
public String getIssuer(String token) {
Claims claims = validToken(token);
return claims.getIssuer();
} /**
* 校验jwtToken,如无效,则返回Null,反之,返回负载对象
*/
private Claims validToken(String token) {
Claims claims = getClaimsFromToken(token);
if (claims != null) {
Date exp = claims.getExpiration();
if (exp.before(new Date())) {
log.warn("# jwtToken已失效:{}", token);
throw new RuntimeException("invalid token");
}
}
return claims;
} /**
* 从token中获取JWT中的负载参数
*/
private Claims getClaimsFromToken(String token) {
Claims claims = null;
try {
claims = Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
} catch (Exception e) {
log.warn("# jwtToken格式验证失败:{}", token, e);
throw new RuntimeException("token verification failed");
}
return claims;
} /** 根据负载参数生成token */
private String generateToken(Claims claims) {
return Jwts.builder().setClaims(claims).signWith(SignatureAlgorithm.HS512, secret).compact();
} /** 获取token有效期 */
private Date getExp() {
return new Date(System.currentTimeMillis() + expiration * 1000);
} public static void main(String[] args) throws ExpiredJwtException, UnsupportedJwtException, MalformedJwtException,
SignatureException, IllegalArgumentException, UnsupportedEncodingException { String username = "yhc"; Claims claims = Jwts.claims();
claims.setIssuer(username); // jwt发行人
claims.setIssuedAt(new Date()); // jwt生成时间
claims.setExpiration(new Date(System.currentTimeMillis() + 3600 * 1000)); // jwt过期时间
claims.setSubject("test"); // jwt主题
claims.setAudience("yhc"); // jwt接受方
claims.setId("uuid"); // jwt唯一身份标识
// claims.setNotBefore(new Date()); // jwt在此之前不可用 String visitTK = Jwts.builder().setClaims(claims).signWith(SignatureAlgorithm.HS512, "sad12f").compact();
System.out.println(visitTK);// SystemValue.JWT_HEADER_VALUE_PREFIX + Claims claimsDecode = Jwts.parser().setSigningKey("sad12f").parseClaimsJws(visitTK).getBody();
System.out.println(claimsDecode.getIssuer()); }
}
以上纯为个人总结,如有错误,还请指出,谢谢。
JWT(Json Wen Token)原理剖析的更多相关文章
- JWT(JSON Web Token)原理简介
原文:http://www.fengchang.cc/post/114 参考了一下这篇文章:https://medium.com/vandium-software/5-easy-steps-to-un ...
- Java JWT: JSON Web Token
Java JWT: JSON Web Token for Java and Android JJWT aims to be the easiest to use and understand libr ...
- JWT(JSON Web Token) 【转载】
JWT(JSON Web Token) 什么叫JWTJSON Web Token(JWT)是目前最流行的跨域身份验证解决方案. 一般来说,互联网用户认证是这样子的. 1.用户向服务器发送用户名和密码. ...
- 5分钟搞懂:JWT(Json Web Token)
https://www.qikegu.com/easy-understanding/892 JWT 基于token的用户认证原理:让用户输入账号和密码,认证通过后获得一个token(令牌),在toke ...
- 温故知新,.Net Core遇见JWT(JSON Web Token)授权机制方案
什么是JWT JWT (JSON Web Token) 是一个开放标准,它定义了一种以紧凑和自包含的方法,用于在双方之间安全地传输编码为JSON对象的信息. 因此,简单来说,它是JSON格式的加密字符 ...
- 如何在SpringBoot中集成JWT(JSON Web Token)鉴权
这篇博客主要是简单介绍了一下什么是JWT,以及如何在Spring Boot项目中使用JWT(JSON Web Token). 1.关于JWT 1.1 什么是JWT 老生常谈的开头,我们要用这样一种工具 ...
- [更新]一份包含: 采用RSA JWT(Json Web Token, RSA加密)的OAUTH2.0,HTTP BASIC,本地数据库验证,Windows域验证,单点登录的Spring Security配置文件
没有任何注释,表怪我(¬_¬) 更新: 2016.05.29: 将AuthorizationServer和ResourceServer分开配置 2016.05.29: Token获取采用Http Ba ...
- ( 转 ) 什么是 JWT -- JSON WEB TOKEN
什么是JWT Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式站点 ...
- 关于JWT(Json Web Token)的思考及使用心得
什么是JWT? JWT(Json Web Token)是一个开放的数据交换验证标准rfc7519(php 后端实现JWT认证方法一般用来做轻量级的API鉴权.由于许多API接口设计是遵循无状态的(比如 ...
- 什么是JWT(Json Web Token)
什么是 JWT (Json Web Token) 用户认证是计算机安全领域一个永恒的热点话题. JWT 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519). 该to ...
随机推荐
- 关于SpringBoot AutoConfiguration
(1)如何导入的自动配置类 首先我们得从@SpringBootApplication注解入手. @SpringBootApplication public class SpringBootDemoAp ...
- Python基础 - 标识符命名规范
标识符是什么? 标识符主要用来给变量名,函数名,方法名,类名起名时要遵循的规范 硬性规则 见名知意(使用中文转译后的英文) 由字母,数字,下划线组成, 并且不能以数字开头, 不能和Python关 ...
- ChatGPT之问艺道:如何借助神级算法Prompt,让你轻松get到更高质量答案?
摘要:本文由葡萄城技术团队编写,文章的内容借鉴于Ibrahim John的<The Art of Asking ChatGPT>(向ChatGPT提问的艺术). 前言 当今,ChatGPT ...
- 时隔多年,从新认识浮动float
开场白 随着css的发展,在加上各种优秀ui库的兴起. 我们在项目中浮动用的很少. 但并不意味着我们不使用浮动了. 曾几何时,浮动这个属性是那个遥远时代的'超级明星' 排版,布局,都需要使用他. 今不 ...
- 3 分钟为英语学习神器 Anki 部署一个专属同步服务器
原文链接:https://icloudnative.io/posts/anki-sync-server/ Anki 介绍 Anki 是一个辅助记忆软件,其本质是一个卡片排序工具--即依据使用者对卡片上 ...
- 探秘高逼格艺术二维码的制作过程-AI绘画文生图
前几天看到几个逼格比较高的二维码,然后自己动手做了一下,给大家看看效果: 1.文生图(狮子): 2.文生图(城市): 下边将开始介绍怎么做的,有兴趣的可以继续读一读. 这里使用的AI绘图工具是Stab ...
- fidder中勾选check for certificate revocations导致手机无法连上fidder服务器
在测试过程中因为要获取一个小程序登录API,就用手机设置代理后抓取,在抓取过程中发现提示用户名密码错误(未使用代理正常登录) 遂逐步查找,在与别人核对tools-option发现自己https页签中勾 ...
- CPython, Pypy, MicroPython...还在傻傻分不清楚?
哈喽大家好,我是咸鱼 当我们说 Python 时,通常指的是官方实现的 CPython 但还有很多比如 Pypy.Jython.MicroPython.Brython.RustPython 等 &qu ...
- 【WebSocket】多节点下WebSocket消息收发解决案例
单体Webscoket springboot版本: 2.1.1.RELEASE jdk: 1.8 示例代码 WebsocketServer @ServerEndpoint("/client/ ...
- 2022-1-20 Wpf绑定属性
使用UpdateSourceTrigger绑定属性 后台绑定 通过后台代码绑定 UpdateSourceTrigger