当前位置: 首页 > news >正文

详细分析Spring Security OAuth2中的JwtAccessTokenConverter基本知识(附Demo)

目录

  • 前言
  • 1. 基本知识
  • 2. Demo
  • 3. 实战

前言

  1. java框架 零基础从入门到精通的学习路线 附开源项目面经等(超全)
  2. 【Java项目】实战CRUD的功能整理(持续更新)

1. 基本知识

JwtAccessTokenConverter 是 Spring Security OAuth2 中的一个重要组件,主要用于生成和验证 JSON Web Token (JWT)

  1. JWT 的结构
    JWT 由三部分组成:头部(Header)、负载(Payload)和签名(Signature)
    头部通常包含令牌的类型(JWT)和签名算法(如 HMAC SHA256)
    负载部分包含声明(Claims),即与用户相关的信息,例如权限、过期时间等
    签名是使用头部和负载生成的,用于验证令牌的完整性

  2. 类继承关系
    JwtAccessTokenConverter 继承自 AbstractTokenConverter,并实现了 AccessTokenConverter 接口
    该类负责将 OAuth2 访问令牌与 JWT 进行转换和处理

  3. 主要方法
    encode:用于生成 JWT,接受 OAuth2AccessToken 和 OAuth2Authentication 参数
    decode:用于解析和验证 JWT,返回 OAuth2AccessToken 实例

常用的几个类如下:

  • Access Token
    OAuth2 中的访问令牌,用于授权客户端访问受保护资源
    JWT 是一种常用的访问令牌格式

  • OAuth2Authentication
    封装与用户相关的身份验证信息,包括用户的身份和权限

  • Additional Information
    JWT 中可以包含附加信息,通常用于存储用户 ID、用户名、权限等自定义字段

2. Demo

  1. 签名密钥:在 main 方法中使用 demo.setSigningKey(signingKey); 设置签名密钥,以确保生成的 JWT 是安全的

  2. 用户权限和身份验证:使用 SimpleGrantedAuthority 创建用户的角色,并通过 TestingAuthenticationToken 实现身份验证

  3. OAuth2AccessToken:创建访问令牌,附加用户 ID、用户名和权限信息

  4. JWT 生成与解码:调用 encode 方法生成 JWT,然后使用 Base64 解码打印出 JWT 的头部和负载部分

常用的xml配置文件如下:

<!-- https://mvnrepository.com/artifact/org.springframework.security.oauth/spring-security-oauth2 -->
<dependency><groupId>org.springframework.security.oauth</groupId><artifactId>spring-security-oauth2</artifactId><version>2.5.0.RELEASE</version>
</dependency>
<dependency><groupId>org.springframework.security</groupId><artifactId>spring-security-jwt</artifactId><version>1.1.0.RELEASE</version> <!-- 确保版本与 Spring Security 兼容 -->
</dependency>

执行代码如下:

package JwtDemo;import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
import org.springframework.security.oauth2.provider.OAuth2Request;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;import java.util.*;public class JwtDemo extends JwtAccessTokenConverter {public static void main(String[] args) {JwtDemo demo = new JwtDemo();String signingKey = "your-signing-key"; // 请替换为你的签名密钥demo.setSigningKey(signingKey);// 创建用户权限Set<SimpleGrantedAuthority> authorities = new HashSet<>();authorities.add(new SimpleGrantedAuthority("ROLE_USER"));// 创建 OAuth2RequestOAuth2Request request = new OAuth2Request(null, "client_id",authorities, true, null, null, null, null, null);// 创建 AuthenticationAuthentication authentication = new TestingAuthenticationToken("user", "password", authorities);// 创建 OAuth2AuthenticationOAuth2Authentication oauth2Authentication = new OAuth2Authentication(request, authentication);// 创建 OAuth2AccessToken 实例DefaultOAuth2AccessToken token = new DefaultOAuth2AccessToken("your-jwt-token");Map<String, Object> additionalInformation = new HashMap<>();additionalInformation.put("user_id", "12345"); // 添加用户信息additionalInformation.put("user_name", "user"); // 添加用户名additionalInformation.put("authorities", authorities); // 添加权限token.setAdditionalInformation(additionalInformation);// 使用 JwtDemo 生成 JWTString jwt = demo.encode(token, oauth2Authentication);System.out.println("生成的 JWT: " + jwt);String[] chunks = jwt.split("\\.");Base64.Decoder decoder = Base64.getUrlDecoder();try {String header = new String(decoder.decode(chunks[0]));String payload = new String(decoder.decode(chunks[1]));System.out.println("Header: " + header);System.out.println("Payload: " + payload);} catch (IllegalArgumentException e) {System.err.println("解码时出错: " + e.getMessage());}}
}// 自定义的 Authentication 实现
class TestingAuthenticationToken extends org.springframework.security.authentication.UsernamePasswordAuthenticationToken {public TestingAuthenticationToken(Object principal, Object credentials, Collection<? extends GrantedAuthority> authorities) {super(principal, credentials, authorities);}
}

截图如下:

在这里插入图片描述

3. 实战

已Bledex源码实战为例

@Configuration  // 标记为配置类,Spring会自动扫描并加载
@ConditionalOnProperty(prefix = "blade.security.oauth2", name = "storeType", havingValue = "jwt", matchIfMissing = true) 
// 当配置中 "blade.security.oauth2.storeType" 为 "jwt" 时,才加载此配置类
public class JwtTokenStoreConfiguration {/*** 使用 jwtTokenStore 存储 token*/@Bean  // 将方法的返回值注册为 Spring 的 Beanpublic TokenStore jwtTokenStore(JwtProperties jwtProperties) {// 创建 JwtTokenStore 实例,并传入 JwtAccessTokenConverterreturn new JwtTokenStore(jwtAccessTokenConverter(jwtProperties));}/*** 用于生成 jwt*/@Bean  // 将方法的返回值注册为 Spring 的 Beanpublic JwtAccessTokenConverter jwtAccessTokenConverter(JwtProperties jwtProperties) {JwtAccessTokenConverter accessTokenConverter = new JwtAccessTokenConverter();// 设置 JWT 签名密钥accessTokenConverter.setSigningKey(jwtProperties.getSignKey());return accessTokenConverter;  // 返回配置好的 JwtAccessTokenConverter}/*** 用于扩展 jwt*/@Bean@ConditionalOnMissingBean(name = "jwtTokenEnhancer") // 当 Spring 容器中没有名为 "jwtTokenEnhancer" 的 Bean 时,才加载此 Beanpublic TokenEnhancer jwtTokenEnhancer(JwtAccessTokenConverter jwtAccessTokenConverter, JwtProperties jwtProperties) {// 创建并返回自定义的 TokenEnhancerreturn new BladeJwtTokenEnhancer(jwtAccessTokenConverter, jwtProperties);}}

对应的自定义类如下:

@AllArgsConstructor  // 自动生成一个包含所有字段的构造函数
public class BladeJwtTokenEnhancer implements TokenEnhancer {private final JwtAccessTokenConverter jwtAccessTokenConverter;  // JWT 访问令牌转换器private final JwtProperties jwtProperties;  // JWT 配置属性@Overridepublic OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {// 从身份验证对象中获取用户的详细信息BladeUserDetails principal = (BladeUserDetails) authentication.getUserAuthentication().getPrincipal();// token 参数增强Map<String, Object> info = new HashMap<>(16);  // 创建一个新的 HashMap 用于存储附加信息info.put(TokenUtil.CLIENT_ID, TokenUtil.getClientIdFromHeader());  // 获取客户端 IDinfo.put(TokenUtil.USER_ID, Func.toStr(principal.getUserId()));  // 获取用户 IDinfo.put(TokenUtil.DEPT_ID, Func.toStr(principal.getDeptId()));  // 获取部门 IDinfo.put(TokenUtil.POST_ID, Func.toStr(principal.getPostId()));  // 获取职位 IDinfo.put(TokenUtil.ROLE_ID, Func.toStr(principal.getRoleId()));  // 获取角色 IDinfo.put(TokenUtil.TENANT_ID, principal.getTenantId());  // 获取租户 IDinfo.put(TokenUtil.OAUTH_ID, principal.getOauthId());  // 获取 OAuth IDinfo.put(TokenUtil.ACCOUNT, principal.getAccount());  // 获取账户信息info.put(TokenUtil.USER_NAME, principal.getUsername());  // 获取用户名info.put(TokenUtil.NICK_NAME, principal.getName());  // 获取昵称info.put(TokenUtil.REAL_NAME, principal.getRealName());  // 获取真实姓名info.put(TokenUtil.ROLE_NAME, principal.getRoleName());  // 获取角色名称info.put(TokenUtil.AVATAR, principal.getAvatar());  // 获取用户头像info.put(TokenUtil.LICENSE, TokenUtil.LICENSE_NAME);  // 获取许可证名称((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(info);  // 将附加信息设置到访问令牌中// token 状态设置if (jwtProperties.getState()) {// 如果 JWT 状态为 true,则增强访问令牌OAuth2AccessToken oAuth2AccessToken = jwtAccessTokenConverter.enhance(accessToken, authentication);String tokenValue = oAuth2AccessToken.getValue();  // 获取增强后的 token 值String tenantId = principal.getTenantId();  // 获取租户 IDString userId = Func.toStr(principal.getUserId());  // 获取用户 ID// 将访问令牌存储到 JwtUtil 中,以便后续管理JwtUtil.addAccessToken(tenantId, userId, tokenValue, accessToken.getExpiresIn());}return accessToken;  // 返回增强后的访问令牌}
}

相关文章:

详细分析Spring Security OAuth2中的JwtAccessTokenConverter基本知识(附Demo)

目录 前言1. 基本知识2. Demo3. 实战 前言 java框架 零基础从入门到精通的学习路线 附开源项目面经等&#xff08;超全&#xff09;【Java项目】实战CRUD的功能整理&#xff08;持续更新&#xff09; 1. 基本知识 JwtAccessTokenConverter 是 Spring Security OAuth2 中的一…...

python习题2

1、输出一个年份&#xff0c;判断其是不是闰年 #输入一个年份&#xff0c;判断其是否是闰年 y eval(input()) if y%4 0 and y%100 ! 0:print("是") elif y%4000:print("是") else:print("不是") 2、模拟智能客服&#xff1a; 按1查询账户余额…...

CVSS 4.0 学习笔记

通用漏洞评分系统(CVSS)捕获了主要技术软件、硬件和固件漏洞的特征。其输出包括数字分数,表明与其他漏洞。 以下因素可能包括但不限于:监管要求、客户数量受影响、因违约造成的金钱损失、生命或财产受到威胁,或潜在漏洞的声誉影响。这些因素在CVSS评估范围之外。 CVSS的好…...

解决 GPTQ 模型导入后推理生成 Tokens 速度很慢的问题(从源码重新安装 Auto-GPTQ)

这里解决的是使用 Auto-GPTQ 或者 Transformers 导入 GPTQ 模型后推理速度很慢的问题。 值得注意的是&#xff0c;这个问题很有可能是因为安装不正确&#xff0c;所以 GPTQ 无法正确使用 GPU 进行推理&#xff0c;也就是说无法进行加速&#xff0c;即便 print(model.device) 显…...

NDC美国药品编码目录数据库查询方法

NDC&#xff08;National Drug Code&#xff09;翻译为“国家药品代码”&#xff0c;是美国食品药品监督管理局&#xff08;FDA&#xff09;制定的一种药品标识系统&#xff0c;用于唯一标识药品。这个编码系统主要目的是为精准识别和追踪不同药品而建设&#xff0c;行业人员和…...

vue3的v-model使用

vue3的v-model使用 单个绑定值 子组件 props: [‘modelValue’], emits: [‘update:modelValue’], 注&#xff1a;modelValue是默认的&#xff0c;如果只有一个需要绑定v-model&#xff0c;可使用modelValue 此时父组件写法 <CustomInput v-model"searchText"…...

Go语言实现长连接并发框架 - 消息

文章目录 前言接口结构体接口实现项目地址最后 前言 你好&#xff0c;我是醉墨居士&#xff0c;上篇博客实现了对连接的封装&#xff0c;那我们对连接的读写操作涉及数据格式的定义&#xff0c;我们采用统一的数据格式。使用我们这种数据格式的数据&#xff0c;我们将其称之为…...

湖南(市场咨询)源点调研 如何明确调研焦点与分析单位的特征

湖南市场调研源点咨询认为&#xff0c;调研过程中定义问题阶段的部分工作涉及弄清究竟是对谁进行调研&#xff0c;也就是感兴趣人群&#xff0c;我们发现这与样本的选择有关。在调研过程的设计阶段弄清楚感兴趣人群非常重要&#xff0c;之后才可以决定选择哪种调研类型进行调研…...

java 方法引用与构造器引用

Java 方法引用和构造器引用是 Java 8 引入的重要特性&#xff0c;它们进一步简化了 Lambda 表达式的书写&#xff0c;使得代码更加简洁和易读。下面详细介绍方法引用和构造器引用的概念、用法及示例。 方法引用 方法引用是一种简化 Lambda 表达式的语法糖&#xff0c;它允许通…...

python3的语法

知识简介 基础语法就像比赛规则&#xff0c;比如比赛跑步&#xff0c;咱们不能跑到别人的跑道去吧&#xff0c;比赛打拳&#xff0c;先说好不能踢裆。 正文 一、python3的基础语法 1、编码 python的源码文件.py一般是utf8编码的&#xff0c;有时候咱们在执行源码文件的时候报…...

Spring Data JPA中的锁机制

当多个事务同时修改同一条记录时&#xff0c;可能会导致数据不一致的问题。为了确保并发事务中的数据一致性&#xff0c;可以使用锁机制。常见的两种锁机制是悲观锁和乐观锁。下面是这两种锁机制的详细讲解。 1. 悲观锁&#xff08;Pessimistic Locking&#xff09; 概念&…...

mybatis分页拦截器

Mapper 方法: public interface UserMapper {void selectUsers(@Param("page") Page<User> page...

React学习过程(持续更新......)

React学习过程&#xff08;持续更新…&#xff09; 创建react的hello项目 使用node创建create-react-app脚手架项目 //首先你得先安装node&#xff0c;这里不做详细教程&#xff0c;我使用的node为20.18.0 npm isntall create-react-app -g //全局安装create-react-app crea…...

pve lxc容器探索,陆续完善中

注意&#xff1a;创建lxc容器时&#xff0c;不要勾选“无特权容器”&#xff0c;才可以使用如下命令进行挂载。 说明&#xff1a;容器附加主机目录&#xff0c;/myweb/src为主机目录&#xff0c;/src为lxc中目录&#xff0c;100为容器ID pct set 100 -mp1 /myweb/src,mp/src执…...

5款人声分离免费软件分享,从入门到精通,伴奏提取分分钟拿捏!

人声分离通常是音乐制作、混音和卡拉OK中常用的重要技术之一。它的核心是将乐器伴奏从原始音轨中分离出来&#xff0c;使得用户可以单独处理或重混音频&#xff0c;创造出清晰干净的伴奏轨道。若缺乏强大的音频剪辑软件或专业人声分离工具&#xff0c;这一过程往往会比较困难。…...

镭速助力解决企业大文件传输难题

在数字化时代&#xff0c;数据已成为企业的核心资产。无论是高清视频、大规模数据库备份还是复杂的3D设计文件&#xff0c;企业每天都要处理大量数据。然而&#xff0c;在享受数据带来的便利和价值的同时&#xff0c;企业也面临着一个现实问题——如何高效、安全地传输大文件&a…...

SpringBootWeb AOP

SpringBootWeb AOP 事务管理 rollbackFor属性 propagation属性 案例 AOP 基础 进阶 通知类型 通知顺序 切入点表达式 execution annotation 连接点 案例 实体类 接口方法 切面类 事务管理 rollbackFor属性 propagation属性 REQUIRED:大部分情况下都是用该传播行为…...

傅里叶分析之掐死教程(完整版)更新于2014.06.06

作 者&#xff1a;韩 昊 知 乎&#xff1a;Heinrich 微 博&#xff1a;花生油工人 知乎专栏&#xff1a;与时间无关的故事 谨以此文献给大连海事大学的吴楠老师&#xff0c;柳晓鸣老师&#xff0c;王新年老师以及张晶泊老师。 转载的同学请保留上面这句话&#xff0c;谢谢。如果…...

macOS终端配置自动补全功能

如何在macOS终端中配置自动补全功能 终端是一个非常强大的工具&#xff0c;它可以用来完成很多任务&#xff0c;比如创建、复制、移动、删除文件&#xff0c;执行脚本和运行程序。不过它的默认设置对用户不太友好&#xff0c;作为开发者&#xff0c;我们通常习惯代码编辑器的辅…...

华为---MUX VLAN简介及示例配置

目录 1. 产生背景 2. 应用场景 3. 主要功能 4. 基本概念 5. 配置步骤及相关命令 6.示例配置 6.1 示例场景 6.2 网络拓扑图 6.3 配置代码 6.4 配置及解析 6.5 测试验证 配置注意事项 1. 产生背景 MUX VLAN&#xff08;Multiplex VLAN&#xff09;提供了一种通过VLA…...

TDengine 快速体验(Docker 镜像方式)

简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能&#xff0c;本节首先介绍如何通过 Docker 快速体验 TDengine&#xff0c;然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker&#xff0c;请使用 安装包的方式快…...

React Native 开发环境搭建(全平台详解)

React Native 开发环境搭建&#xff08;全平台详解&#xff09; 在开始使用 React Native 开发移动应用之前&#xff0c;正确设置开发环境是至关重要的一步。本文将为你提供一份全面的指南&#xff0c;涵盖 macOS 和 Windows 平台的配置步骤&#xff0c;如何在 Android 和 iOS…...

大数据零基础学习day1之环境准备和大数据初步理解

学习大数据会使用到多台Linux服务器。 一、环境准备 1、VMware 基于VMware构建Linux虚拟机 是大数据从业者或者IT从业者的必备技能之一也是成本低廉的方案 所以VMware虚拟机方案是必须要学习的。 &#xff08;1&#xff09;设置网关 打开VMware虚拟机&#xff0c;点击编辑…...

2025盘古石杯决赛【手机取证】

前言 第三届盘古石杯国际电子数据取证大赛决赛 最后一题没有解出来&#xff0c;实在找不到&#xff0c;希望有大佬教一下我。 还有就会议时间&#xff0c;我感觉不是图片时间&#xff0c;因为在电脑看到是其他时间用老会议系统开的会。 手机取证 1、分析鸿蒙手机检材&#x…...

土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等

&#x1f50d; 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术&#xff0c;可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势&#xff0c;还能有效评价重大生态工程…...

JDK 17 新特性

#JDK 17 新特性 /**************** 文本块 *****************/ python/scala中早就支持&#xff0c;不稀奇 String json “”" { “name”: “Java”, “version”: 17 } “”"; /**************** Switch 语句 -> 表达式 *****************/ 挺好的&#xff…...

汇编常见指令

汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX&#xff08;不访问内存&#xff09;XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...

SpringCloudGateway 自定义局部过滤器

场景&#xff1a; 将所有请求转化为同一路径请求&#xff08;方便穿网配置&#xff09;在请求头内标识原来路径&#xff0c;然后在将请求分发给不同服务 AllToOneGatewayFilterFactory import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; impor…...

uniapp中使用aixos 报错

问题&#xff1a; 在uniapp中使用aixos&#xff0c;运行后报如下错误&#xff1a; AxiosError: There is no suitable adapter to dispatch the request since : - adapter xhr is not supported by the environment - adapter http is not available in the build 解决方案&…...

(转)什么是DockerCompose?它有什么作用?

一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用&#xff0c;而无需手动一个个创建和运行容器。 Compose文件是一个文本文件&#xff0c;通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...