赞
踩
首先我们需要一个Json
{
"alg":"HS256"
}
接着我们需要将其在Java中展示出来
String header = "{\n" +
"\t\"alg\":\"HS256\"\n" +
"}";
之后要去除所有空格
String header = "{"alg":"HS256"}";
报错了,很明显是有问题的,接着用转义字符将“正常展示出来
String header = "{\"alg\":\"HS256\"}";
此时我们将这个字符串用Base64URL进行编码,这里使用基于Commons Codec的URLBase64编码
<!--Commons Codec依赖-->
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.15</version>
</dependency>
byte[] encodeHeaderBytes = Base64.encodeBase64URLSafe(header.getBytes("UTF-8"));
然后把byte数组转为字符串
String encodeHeader = new String(encodeHeaderBytes);
此时可以尝试输出此字符串,理论上应当如下,这也是此JWT的头部
eyJhbGciOiJIUzI1NiJ9
JWT官网调试器调试无误,可以正常解析JWT标头
首先随便来个有内容的JSON,如下
{
"sub":"可达鸭"
}
之后和头部做同样的处理,最终输出的内容应当如下
eyJzdWIiOiLlj6_ovr7puK0ifQ
然后将头部和载荷用.拼接,如下
String s = encodeHeader+"."+encodeClaims;
//输出结果eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiLlj6_ovr7puK0ifQ
JWT官网调试器调试无误,可以正常解析JWT标头及载荷
首先我们需要一个自己生成的密钥,或者说加密盐,他可以只是一个简单的123456,也可以是经过复杂处理的字符串
String secret = "123456";//普通密钥
之后用HmacSHA256对之前拼接好的字符串加密,并用Base64URL进行编码
String message = encodeHeader + "." + encodeClaims;
Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
SecretKeySpec secret_key = new SecretKeySpec(secret.getBytes(), "HmacSHA256");
sha256_HMAC.init(secret_key);
String verifySignature = new String(Base64.encodeBase64URLSafe(sha256_HMAC.doFinal(message.getBytes())));
最终将标头和载荷、签名通过.进行拼接,就得到了以下字符串
eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiLlj6_ovr7puK0ifQ.2AHwp9OhaBwj2uNlXTGSzyaIfym7hrA2_ubRx4E9xd4
将其放入JWT官网,验证通过并且解析无误
这里是本人在进行手动生成JWT时遇到的问题
1.Base64编码头部和官方编码结果有较小差距
解决:
官方使用的是Base64URL编码,并不是Base64编码
Base64URL编码对比Base64编码增强了对浏览器的适应性,Base64编码时编码为+的转为-(减法符号),编码为/的转为_(下划线)并且去掉末尾的=(等号)
2.使用Base64URL编码后数据依然有出入
解决:
模拟的JSON数据双引号使用’进行替代了,替换为"转义就可以了
3.签名字符完全错误
解决:
原本的做法是对HmacSHA256加密后的签名直接进行toHexString的方式将其显示出来(HmacSHA256加密的byte数组正常无法显示),后来发现官方的做法是对此byte数组进行Base64URL编码,修改后无错
4.官方调试器下的secret base64 encode(此问题浪费了我2小时的生命)
解决:
从始至终我都认为这个选项勾选上的意思是,这个选项的意思是
原本我的secret(盐)值为123456,勾选上后会将123456进行base64编码再作为secret进行HmacSHA256(你所选择的签名加密方式)加密,相信大部分人都是这么认为的。
但是我在代码上重现了这一操作后发现和官方得到的JWT签名完全是不同的。
于是我有了另一个猜想,勾选此选项后是否不再对最后得到的byte数组进行base64URL编码,后经过验证,猜想错误。
之后又尝试了将很多不正常的想法,花费了大量的时间,在我快准备放弃的时候,我想起了百度,于是我百度了一下,JWT官网的secret base64 encode是什么意思,以下是得到的答案:
JWT官网的secret base64 encode意思是将secret视为经过base64编码产生的,先对其进行base64decode(解码)操作,再将其作为secret进行HmacSHA256加密,测试无误。
Base64 base64 = new Base64(); byte[] secret = new Base64().encode("123456".getBytes("UTF-8"));//复杂密钥 System.out.println("Base64编码盐:" + new String(secret)); //Base64加密盐:MTIzNDU2 String message = encodeHeader + "." + encodeClaims; Mac sha256_HMAC = Mac.getInstance("HmacSHA256"); SecretKeySpec secret_key = new SecretKeySpec(secret, "HmacSHA256"); sha256_HMAC.init(secret_key); String verifySignature = new String(Base64.encodeBase64URLSafe(sha256_HMAC.doFinal(message.getBytes()))); System.out.println("Base64编码盐最终签名:" + verifySignature); //Base64加密盐最终签名:V7TXJxLIij3gduj6b_8oGQ6K_RmA3kd43S8RrOB554s secret_key = new SecretKeySpec("123456".getBytes("UTF-8"),"HmacSHA256"); sha256_HMAC.init(secret_key); verifySignature = new String(Base64.encodeBase64URLSafe(sha256_HMAC.doFinal(message.getBytes()))); System.out.println("123456编码盐最终签名:" + verifySignature); //123456加密盐最终签名:2AHwp9OhaBwj2uNlXTGSzyaIfym7hrA2_ubRx4E9xd4
最后更新于2021年4月17日
原创不易,如果该文章对你有所帮助,望左上角点击关注~如有任何技术相关问题,可通过评论联系我讨论,我会在力所能及之内进行相应回复以及开单章解决该问题.
该文章如有任何错误请在评论中指出,感激不尽,转载请附出处!
*个人博客首页:https://blog.csdn.net/yjrguxing ——您的每个关注和评论都对我意义重大
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。