payload与claims只能存在一个
这部分是jwt源码:
依赖如下:官方文档的依赖
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.2</version>
</dependency>

<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.2</version>
</dependency>

<dependency>
<groupId>io.jsonwebtoken </groupId >
<artifactId>jjwt-jackson </artifactId >
<version>0.11.2</version>
</dependency>


2020-11-1217:17:43
@Override
public String compact() { if (this.serializer == null) {
// try to find one based on the services available
// TODO: This util class will throw a UnavailableImplementationException here to retain behavior of previous version, remove in v1.0
// use the previous commented out line instead
this.serializer = LegacyServices.loadFirst(Serializer.class);
} if (payload == null && Collections.isEmpty(claims)) {//判断空
payload = "";
} if (payload != null && !Collections.isEmpty(claims)) {//判断空
throw new IllegalStateException("Both 'payload' and 'claims' cannot both be specified. Choose either one.");
} Header header = ensureHeader(); JwsHeader jwsHeader;
if (header instanceof JwsHeader) {//判断header类型
jwsHeader = (JwsHeader) header;
} else {
//noinspection unchecked
jwsHeader = new DefaultJwsHeader(header);
} if (key != null) { //判断加密方式
jwsHeader.setAlgorithm(algorithm.getValue());
} else {
//no signature - plaintext JWT:
jwsHeader.setAlgorithm(SignatureAlgorithm.NONE.getValue());
} if (compressionCodec != null) {
jwsHeader.setCompressionAlgorithm(compressionCodec.getAlgorithmName());
}
//header进行base64加密
String base64UrlEncodedHeader = base64UrlEncode(jwsHeader, "Unable to serialize header to json.");
//绿色部分表示payload转化base64加密成字节数组进行一次压缩
byte[] bytes;
try {
bytes = this.payload != null ? payload.getBytes(Strings.UTF_8) : toJson(claims);
} catch (SerializationException e) {
throw new IllegalArgumentException("Unable to serialize claims object to json: " + e.getMessage(), e);
} if (compressionCodec != null) {
bytes = compressionCodec.compress(bytes);
}
//对payload压缩后的租界数组再来一次base64加密
String base64UrlEncodedBody = base64UrlEncoder.encode(bytes);
//签名拼接
String jwt = base64UrlEncodedHeader + JwtParser.SEPARATOR_CHAR + base64UrlEncodedBody;


// 加密的key再次判断为不为空
if (key != null) { //jwt must be signed:
//签名与拼接
JwtSigner signer = createSigner(algorithm, key); String base64UrlSignature = signer.sign(jwt); jwt += JwtParser.SEPARATOR_CHAR + base64UrlSignature;
} else {
// no signature (plaintext), but must terminate w/ a period, see
// https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-6.1
jwt += JwtParser.SEPARATOR_CHAR;
} return jwt;
}

个人模拟加密流程:


        //0  原始签名
String header0 = "{\"alg\":\"HS256\"}";
String claims0 = "{\"sub\":\"wangbiao\",\"aud\":\"wangbiao\"}"; Encoder<byte[], String> base64UrlEncoder = Encoders.BASE64URL;
String hed =base64UrlEncoder.encode(header0.getBytes("UTF-8")); Map map= (Map) JSON.parse(claims0);
Serializer<Map<String,?>> serializer= LegacyServices.loadFirst(Serializer.class);
byte[] clambyte0= serializer.serialize(map); /**
* payload为空String方法转化字节数组,不然转化JSON序列化,默认payload为null 即上面的序列化
* bytes = this.payload != null ? payload.getBytes(Strings.UTF_8) : toJson(claims);
* byte [] claimbyte=claims0.getBytes("UTF-8");
*/ /**
* 默认jwt不需要压缩
* DeflateCompressionCodeWb deflateCompressionCodecss=new DeflateCompressionCodeWb();
* claims压缩字节
* byte[] clambyte1 =deflateCompressionCodecss.doCompress(clambyte0);
*/ // KeyPair keyPair = Keys.keyPairFor(SignatureAlgorithm.RS256);
//签名key
SecretKey key = Keys.secretKeyFor(SignatureAlgorithm.HS256); //字节在编码
String cla= base64UrlEncoder.encode(clambyte0);
String concatenated= hed+'.'+cla; //签名方式
SignatureAlgorithm algorithm=SignatureAlgorithm.HS256; JwtSigner defaultJwtBuilder=new DefaultJwtSigner(algorithm,key,base64UrlEncoder); String base64UrlSignature = defaultJwtBuilder.sign(concatenated);
String sss= concatenated+'.'+base64UrlSignature;
// System.out.println(sss);
//验签
System.out.println(Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(sss));

利用jwt封装的方法:

        //2设置token方式二 设置头
Header header = new DefaultHeader();
header.put("alg", "HS256");
// //header设置方式1 设置map
Map<String, Object> claims = new HashMap<>();
claims.put("aud", "wangbiao");
claims.put("sub", "wangbiao");
String jwss = Jwts.builder()
.setHeader((Map<String, Object>) header)
.setClaims(claims)
.signWith(key)
.compact();
// System.out.println(jwss);
//验签
System.out.println(Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(jwss));

个人jwt生成结果:

eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ3YW5nYmlhbyIsImF1ZCI6IndhbmdiaWFvIn0.Lxso52KaEnj_a7mYAoH0eoPisIpCo_2sBihmf7sHxGw
jwt封装生成结果:

eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJ3YW5nYmlhbyIsInN1YiI6IndhbmdiaWFvIn0.weI8QvS16782iZR6Hb3k3kYExmpSyax0a-KRzfG-vFc
可以看出最后签名不一致

个人jwt验签解析:

header={alg=HS256},body={sub=wangbiao, aud=wangbiao},signature=Lxso52KaEnj_a7mYAoH0eoPisIpCo_2sBihmf7sHxGw

jwt封装眼前解析:

header={alg=HS256},body={aud=wangbiao, sub=wangbiao},signature=weI8QvS16782iZR6Hb3k3kYExmpSyax0a-KRzfG-vFc

思考:通过追踪源码:发现默认情况下payload没有进行压缩

即没有进行如下操作:

if (compressionCodec != null) {
bytes = compressionCodec.compress(bytes);
}
               payload为bull进行字符String转化为字节数组,不然转化为转化为tojSON(claims)序列化
bytes = this.payload != null ? payload.getBytes(Strings.UTF_8) : toJson(claims);

header正常进行base64加密

猜想:我此处使用main方法测试,同一个线程下jwt签名具有不可重复,或者jwt默认就是签名不可重复

header={alg=HS256},body={aud=wangbiao, sub=wangbiao},signature=weI8QvS16782iZR6Hb3k3kYExmpSyax0a-KRzfG-vFc

官方文档有如下说明:意思就是如果在一个系统中使用不同的key需要自己重写,密匙解析器,好处就是方便不同的业务使用不同的加密方法,利用适配器的思想解决不同类型的key从而进行验签

:看源码太累,有哪位大神按照如下思路出个方案,共同进步

签名密钥分解器
如果您的应用程序期望使用不同的键签名的JWSs,您就不会调用setSigningKey方法。相反,您需要实现SigningKeyResolver接口,并通过setSigningKeyResolver方法在JwtParserBuilder上指定一个实例。
例如:
SigningKeyResolver signingKeyResolver = getMySigningKeyResolver(); Jwts.parserBuilder () .setSigningKeyResolver (signingKeyResolver) / / <— .build ()
.parseClaimsJws (jwsString);
通过扩展SigningKeyResolverAdapter并实现resolveSigningKey(JwsHeader, Claims)方法,可以简化一些事情。例如:
public class MySigningKeyResolver extends SigningKeyResolverAdapter { @Override
public Key resolveSigningKey(JwsHeader jwsHeader, Claims claims) {
// implement me
}
}
JwtParser将在解析JWS JSON之后,但在验证JWS签名之前调用resolveSigningKey方法。这允许您检查JwsHeader并声明任何可以帮助您查找用于验证特定jws的键的信息。这对于具有更复杂安全模型的应用程序非常强大,这些应用程序可能在不同的时间使用不同的密钥,或者针对不同的用户或客户。
您可能会检查哪些数据?
JWT规范支持的方法是在创建JWS时在JWS头部设置一个kid (Key ID)字段,例如: getSigningKey(); getKeyId(signingKey);//任何将密钥与ID关联的机制都可以 jws .builder() .setHeaderParam (JwsHeader。KEY_ID, keyId) // 1 .signWith (signingKey) / / 2 .compact ();
然后在解析期间,SigningKeyResolver可以检查JwsHeader以获取kid,然后使用该值从某个地方(比如数据库)查找键。例如:
public class MySigningKeyResolver extends SigningKeyResolverAdapter { @Override
public Key resolveSigningKey(JwsHeader jwsHeader, Claims claims) { //inspect the header or claims, lookup and return the signing key String keyId = jwsHeader.getKeyId(); //或任何其他字段,你需要检查
Key key = lookupVerificationKey(keyId); //实现我 return key;
}
}
注意,检查jwsHeader.getKeyId()只是查找键的最常见方法—您可以检查任意数量的头字段或声明,以确定如何查找验证键。这完全取决于JWS是如何创建的。
最后请记住,对于HMAC算法,返回的验证密钥应该是一个秘钥,而对于非对称算法,返回的密钥应该是一个公钥(而不是一个私钥)。

jwt《token》的更多相关文章

  1. ASP.NET WebApi 基于JWT实现Token签名认证

    一.前言 明人不说暗话,跟着阿笨一起玩WebApi!开发提供数据的WebApi服务,最重要的是数据的安全性.那么对于我们来说,如何确保数据的安全将会是需要思考的问题.在ASP.NET WebServi ...

  2. 微信公众号开发《三》微信JS-SDK之地理位置的获取,集成百度地图实现在线地图搜索

    本次讲解微信开发第三篇:获取用户地址位置信息,是非常常用的功能,特别是服务行业公众号,尤为需要该功能,本次讲解的就是如何调用微信JS-SDK接口,获取用户位置信息,并结合百度地铁,实现在线地图搜索,与 ...

  3. 微信公众号开发《三》微信JS-SDK之地理位置的获取与在线导航,集成百度地图实现在线地图搜索

    本次讲解微信开发第三篇:获取用户地址位置信息,是非常常用的功能,特别是服务行业公众号,尤为需要该功能,本次讲解的就是如何调用微信JS-SDK接口,获取用户位置信息,并结合百度地铁,实现在线地图搜索,与 ...

  4. 深入理解SpringBoot核心机制《spring-boot-starter》

    深入理解SpringBoot核心机制<spring-boot-starter> 前言: 对于这几年java火爆天的springBoot我相信大家都有所使用过,在springBoot的项目中 ...

  5. 天河微信小程序入门《四》:融会贯通,form表单提交数据库

    天河在阔别了十几天之后终于又回来了.其实这篇文章里的demo是接着(天河微信小程序入门<三>)后面就做了的,但是因为最近在做别的项目,所以就偷懒没有发出来.放到今天来看,从前台提交数据到数 ...

  6. 天河微信小程序入门《三》:打通任督二脉,前后台互通

    原文链接:http://www.wxapp-union.com/forum.php?mod=viewthread&tid=505&extra=page%3D1 天河君在申请到https ...

  7. 《社交网络》里的评分公式——ELO排名系统

    <社交网络>里的Mark Zackburg被女朋友甩后,在舍友的启发下,充分发挥了技术宅男自娱自乐的恶搞天分,做出了Facemash网站,对学校女生的相貌进行排名打分,结果网站访问流量过大 ...

  8. 原创:从零开始,微信小程序新手入门宝典《一》

    为了方便大家了解并入门微信小程序,我将一些可能会需要的知识,列在这里,让大家方便的从零开始学习:一:微信小程序的特点张小龙:张小龙全面阐述小程序,推荐通读此文: 小程序是一种不需要下载.安装即可使用的 ...

  9. 《InsideUE4》GamePlay架构(十)总结

    世界那么大,我想去看看 引言 通过对前九篇的介绍,至此我们已经了解了UE里的游戏世界组织方式和游戏业务逻辑的控制.行百里者半九十,前述的篇章里我们的目光往往专注在于特定一个类或者对象,一方面固然可以让 ...

随机推荐

  1. 让Angular自定义组件支持form表单验证

    Angular提供了一套非常强大的表单验证库(vue和react都需要第三方库的支持),可以非常方便简单实现web应用程序中的表单验证功能.但是如何让我们自定义的组件也支持验证呢? 我遇到一个需求是封 ...

  2. 在Java中,负数的绝对值竟然不一定是正数!!!

    绝对值是指一个数在数轴上所对应点到原点的距离,所以,在数学领域,正数的绝对值是这个数本身,负数的绝对值应该是他的相反数. 这几乎是每个人都知道的. 在Java中,想要获得有个数字的绝对值,可以使用ja ...

  3. PAT甲级:1089 Insert or Merge (25分)

    PAT甲级:1089 Insert or Merge (25分) 题干 According to Wikipedia: Insertion sort iterates, consuming one i ...

  4. 以太坊-Win环境下remix环境搭建

    一.node.js环境搭建 有多个安装方法,但是注意npm与node版本相关性较强!以下方案较为简便 1.下载网址 http://nodejs.cn/download/ 2.下载window 64位 ...

  5. SSM中如何上传图片

    1.文件配置 2.jsp页面 文件的name值不能跟数据库列名一致 3.控制层收集数据转发到逻辑层 4.逻辑层处理把用户信息存到数据库 5.注册成功后跳到jsp页面进行展示

  6. 用activiti实现类似钉钉审批流程-附整个系统源码

    前言 目前市场上有很多开源平台没有整合工作流,即使有,也是价格不菲的商业版,来看这篇文章的估计也了解了行情,肯定不便宜.我这个快速开发平台在系统基础功能(用户管理,部门管理-)上整合了工作流,你可以直 ...

  7. SimpleDateFormat类的线程安全问题和解决方案

    摘要:我们就一起看下在高并发下SimpleDateFormat类为何会出现安全问题,以及如何解决SimpleDateFormat类的安全问题. 本文分享自华为云社区<SimpleDateForm ...

  8. window.location.href下载文件,文件名中文乱码处理

    下载文件方法: window.location.href='http://www.baidu.com/down/downFile.txt?name=资源文件'; 这种情况下载时:文件名资源文件会中文乱 ...

  9. OpenGL学习笔记(三)着色器

    目录 Shader是什么 GLSL 数据类型 输入与输出 顶点着色器向片段着色器发送数据 Uniform 制作三色渐变三角形 对着色器程序进行封装 参考资料:OpenGL中文翻译 Shader是什么 ...

  10. Android:Camera2的简单使用

    以前用的是Camera,但是现在Camera已经被官方弃用了,所以这里使用的是Camera2进行演示 使用Camera需要注意的就是权限的获取,必须有权限 类图介绍 Camera2跟Camera1不一 ...