JwtAccessTokenConverter问题整理
Cannot convert access token to JSON
授权服务颁发token(未进行公私钥加密)后,携带此token请求资源服务,提示此错误。
使用token可以在线解析,跟踪代码后问题出现JwtHelper
类decodeAndVerify方法,内容如下:
...
public static Jwt decodeAndVerify(String token, SignatureVerifier verifier) {
Jwt jwt = decode(token);
jwt.verifySignature(verifier);
return jwt;
}
...
其中jwt.verifySignature(verifier)中verifier为空,在下一层JwtImpl
类中,方法如下:
...
public void verifySignature(SignatureVerifier verifier) {
verifier.verify(this.signingInput(), this.crypto);
}
...
所以在资源服务中,必须对JwtAccessTokenConverter
初始化setVerifier。
...
/**
* Description: 为签名验证和解析提供转换器<br>
* Details: 看起来 {@link org.springframework.security.jwt.crypto.sign.RsaVerifier} 已经被标记为过时了, 究其原因, 似乎 Spring 已经发布了一个新的产品 Spring Authorization Server, 有空再研究.
*
* @see <a href="https://github.com/spring-projects/spring-security/wiki/OAuth-2.0-Migration-Guide">OAuth 2.0 Migration Guide</a>
* @see <a href="https://spring.io/blog/2020/04/15/announcing-the-spring-authorization-server">Announcing the Spring Authorization Server</a>
* @see JwtAccessTokenConverter
*/
@SuppressWarnings("deprecation")
private JwtAccessTokenConverter jwtAccessTokenConverter() {
final JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
jwtAccessTokenConverter.setVerifier(new org.springframework.security.jwt.crypto.sign.RsaVerifier(retrievePublicKey()));
return jwtAccessTokenConverter;
}
/**
* Description: 获取公钥 (Verifier Key)<br>
* Details: 启动时调用
*
* @return java.lang.String
* @author LiKe
* @date 2020-07-22 11:45:40
*/
private String retrievePublicKey() {
final ClassPathResource classPathResource = new ClassPathResource(AUTHORIZATION_SERVER_PUBLIC_KEY_FILENAME);
try (
// ~ 先从本地取读取名为 authorization-server.pub 的公钥文件, 获取公钥
final BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(classPathResource.getInputStream()))
) {
log.debug("{} :: 从本地获取公钥 ...", RESOURCE_ID);
return bufferedReader.lines().collect(Collectors.joining("\n"));
} catch (IOException e) {
// ~ 如果本地没有, 则尝试通过授权服务器的 /oauth/token_key 端点获取公钥
log.debug("{} :: 从本地获取公钥失败: {}, 尝试从授权服务器 /oauth/token_key 端点获取 ...", RESOURCE_ID, e.getMessage());
final RestTemplate restTemplate = new RestTemplate();
final String responseValue = restTemplate.getForObject(AUTHORIZATION_SERVER_TOKEN_KEY_ENDPOINT_URL, String.class);
log.debug("{} :: 授权服务器返回原始公钥信息: {}", RESOURCE_ID, responseValue);
return JSON.parseObject(JSON.parseObject(responseValue).getString("data")).getString("value");
}
}
...
最终定位出现问题是因为没有正确初始化signingKey
与verifierKey
。
先说说 verifierKey 和 verifier, 默认值是一个 6 位的随机字符串 (new RandomValueStringGenerator().generate()), 和它 “配套” 的 verifier 是持有这个 verifierKey 的 MacSigner (用 HMACSHA256 算法验证 Signature) / RsaVerifier (用 RSA 公钥验证 Signature), 在 JwtAccessTokenConverter 的 decode 方法中作为签名校验器被传入 JwtHelper 的 decodeAndVerify(@NotNull String token, org.springframework.security.jwt.crypto.sign.SignatureVerifier verifier)
下面例子为使用原始MacSigner HMACSHA256 算法
例子:
...
private JwtAccessTokenConverter jwtAccessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey("***");
try {
converter.afterPropertiesSet();
} catch (Exception e) {
e.printStackTrace();
}
return converter;
}
...
最后问题完美解决。
而在 JwtHelper 的目标方法中, 首先把 token 的三个部分 (以 . 分隔的) 拆分出来, Base64.urlDecode 解码. 再用我们传入的 verifier 将 “Header.Payload” 编码 (如果是 RSA, 就是公钥.) 并与拆分出来的 Signature 部分比对 (Reference: org.springframework.security.jwt.crypto.sign.RsaVerifier#verify).
对应的, signer 和 signingKey 作为签名 “组件” 存在, (可以看到在默认情况下, JwtAccessTokenConverter 对 JWT 的 Signature 采用的是对称加密, signingKey 和 verifierKey 一致) 在 JwtHelper 的 encode(@NotNull CharSequence content, @NotNull org.springframework.security.jwt.crypto.sign.Signer signer) 方法中, 被用于将 “Header.Payload” 加密 (如果是 RSA, 就是私钥) (Reference: org.springframework.security.jwt.crypto.sign.RsaSigner#sign).
所以算法本质上不是对 JWT 整体进行加解密, 而是对其中的 Signature 部分
参考
Java JwtAccessTokenConverter.setVerifierKey方法代碼示例 - 純淨天空 (vimsky.com)
JwtAccessTokenConverter问题整理的更多相关文章
- dotNET跨平台相关文档整理
一直在从事C#开发的相关技术工作,从C# 1.0一路用到现在的C# 6.0, 通常情况下被局限于Windows平台,Mono项目把我们C#程序带到了Windows之外的平台,在工作之余花了很多时间在M ...
- UWP学习目录整理
UWP学习目录整理 0x00 可以忽略的废话 10月6号靠着半听半猜和文字直播的补充看完了微软的秋季新品发布会,信仰充值成功,对UWP的开发十分感兴趣,打算后面找时间学习一下.谁想到学习的欲望越来越强 ...
- SQL Server 常用内置函数(built-in)持续整理
本文用于收集在运维中经常使用的系统内置函数,持续整理中 一,常用Metadata函数 1,查看数据库的ID和Name db_id(‘DB Name’),db_name('DB ID') 2,查看对象的 ...
- kafka学习笔记:知识点整理
一.为什么需要消息系统 1.解耦: 允许你独立的扩展或修改两边的处理过程,只要确保它们遵守同样的接口约束. 2.冗余: 消息队列把数据进行持久化直到它们已经被完全处理,通过这一方式规避了数据丢失风险. ...
- JAVA程序员常用软件整理下载
********为了大家学习方便,特意整理软件下载如下:*************Java类软件:-------------------------------JDK7.0:http://pan.ba ...
- js数组学习整理
原文地址:js数组学习整理 常用的js数组操作方法及原理 1.声明数组的方式 var colors = new Array();//空的数组 var colors = new Array(3); // ...
- GJM : C#设计模式汇总整理——导航 【原创】
感谢您的阅读.喜欢的.有用的就请大哥大嫂们高抬贵手"推荐一下"吧!你的精神支持是博主强大的写作动力以及转载收藏动力.欢迎转载! 版权声明:本文原创发表于 [请点击连接前往] ,未经 ...
- 整理下.net分布式系统架构的思路
最近看到有部分招聘信息,要求应聘者说一下分布式系统架构的思路.今天早晨正好有些时间,我也把我们实际在.net方面网站架构的演化路线整理一下,只是我自己的一些想法,欢迎大家批评指正. 首先说明的是.ne ...
- 安卓GreenDao框架一些进阶用法整理
大致分为以下几个方面: 一些查询指令整理 使用SQL语句进行特殊查询 检测表字段是否存在 数据库升级 数据库表字段赋初始值 一.查询指令整理 1.链式执行的指令 return mDaoSession. ...
随机推荐
- No shutdown animation in the electricity display only 1%
低电量自动关机时无关机动画 低电量自动关机时无关机动画1. 问题描述2. 分析3. solution4. 总结 1. 问题描述 DEFECT DESCRIPTION: No shutdown anim ...
- WEB开发的相关知识(Tomcat)
Internet上供外界访问的Web资源分为 静态web资源(如html 页面):指web页面中供人们浏览的数据始终是不变. 动态web资源:指web页面中供人们浏览的数据是由程序产生的,不同时间点访 ...
- 《剑指offer》面试题57. 和为s的两个数字
问题描述 输入一个递增排序的数组和一个数字s,在数组中查找两个数,使得它们的和正好是s.如果有多对数字的和等于s,则输出任意一对即可. 示例 1: 输入:nums = [2,7,11,15], tar ...
- 2月3日 体温APP开发记录
1.阅读构建之法 现代软件工程(第三版) 2.观看Android开发视频教程最新版 Android Studio开发 3.回返地址学习,下载导入相关jar包
- logrotate 日志切割
logrotate是一个日志文件管理工具.用于分割日志文件,删除旧的日志文件,并创建新的日志文件,起到"转储"作用. 配置文件 Linux系统默认安装logrotate工具,它默认 ...
- 查看Linux系统信息
1.查看内核 [root@localhost etc]# uname -aLinux localhost.localdomain 3.10.0-514.el7.x86_64 #1 SMP Tue No ...
- ApacheCN JavaScript 译文集(二) 20211123 更新
使用 Meteor 构建单页 Web 应用 零.前言 一.制作 Meteor 应用 二.构建 HTML 模板 三.存储数据和处理集合 四.控制数据流 五.使我们的应用与路由通用 六.保持会话状态 七. ...
- 【第十二期】腾讯后台实习初试、复试、HR面经 (许愿OC)
楼主投的很晚属于正常批才开始,初试面试官比较重基础,复试面试官比较看综合能力,HR小姐姐声音好听,腾讯面试官都特别nice! 一面: 看你项目很多,你挨个给我介绍一遍吧 我:一大堆按着简历介绍 日志文 ...
- AT2689 [ARC080D] Prime Flip
简要题解如下: 区间修改问题,使用差分转化为单点问题. 问题变成,一开始有 \(2n\) 个点为 \(1\),每次操作可以选择 \(r - l\) 为奇质数的两个点 \(l, r\) 使其 ^ \(1 ...
- IIS部署.net core 的程序后,如何查看控制台的日志?
.net core 3.1 开发的web服务,本地开发的时候,双击运行 xxx.exe(.net core 3.1 发布后,文件夹里面有一个 .exe 文件,双击即可运行,会直接监听本地 xx端口测试 ...