详细分析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;  // 返回增强后的访问令牌}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1556412.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

如何创建免费版本的ABP分离模块?

由于ABP最近官方大改革&#xff0c;我们打开ABP.IO 官方会发现通过Cli创建模板的时候不能创建Trered类型的了 就是创建一个分层的解决方案&#xff0c;其中Web和Http API层在物理上是分开的。如果不勾选&#xff0c;则创建一个分层的解决方案&#xff0c;它不那么复杂&#xf…

Taipy:AI应用全栈开发神器

Taipy 是一个免费使用的 Python 库&#xff0c;任何具备基本 Python 技能的人都可以使用。它是数据科学家、机器学习工程师和 Python 程序员的得力工具。使用 Taipy&#xff0c;你可以轻松地将数据和机器学习模型转换为功能齐全的 Web 应用程序。在我们生活的瞬息万变的世界中&…

SpringBoot:让开发更加简单

文章目录 前言什么是 SpringBoot快速启动一个 SpringBoot 项目开发一个登录功能小结 前言 有一天&#xff0c;你脑海中闪现了一个想法&#xff1a;“学了 Java 好像还没怎么使用&#xff0c;今天要不用 Java 开发一个自己的网站&#xff1f;” 你想着不禁激动起来&#xff0c;…

棋牌灯控计时计费系统软件免费试用版怎么下载 佳易王计时收银管理系统操作教程

一、前言 【试用版软件下载&#xff0c;可以点击本文章最下方官网卡片】 棋牌灯控计时计费系统软件免费试用版怎么下载 佳易王计时收银管理系统操作教程 棋牌计时计费软件的应用也提升了顾客的服务体验&#xff0c;顾客可以清晰的看到自己的消费时间和费用。增加了消费的透明…

NASA:GES DISC 的 ATMOS L1 光谱和运行日志 V3 (ATMOSL1)大气痕量分子光谱(ATMOS)1 级产品

目录 简介 变量 代码 引用 网址推荐 0代码在线构建地图应用 机器学习 ATMOS L1 Spectra and Runlogs V3 (ATMOSL1) at GES DISC 简介 这是第三版大气痕量分子光谱&#xff08;ATMOS&#xff09;1 级产品&#xff0c;包含 netCDF 格式的光谱和运行日志&#xff08;即 &…

Codeforces Round 977

这场比赛是晚上vp的&#xff0c;太逆天了自己&#xff0c;给我自己都菜笑了&#xff0c;第二题当时差了一个那个循序渐进的点没想到&#xff0c;关键细节都想到了&#xff0c;当时以为是错的就没写&#xff0c;第二题没做出来确实好久没遇到过了&#xff0c;裂开 话不多说&…

WMCTF 2024 wp

WEB PasswdStealer 前言 本来题目叫PasswdStealer的&#xff1a;) 考点就是CVE-2024-21733在SpringBoot场景下的利用。 漏洞基本原理参考 https://mp.weixin.qq.com/s?__bizMzg2MDY2ODc5MA&mid2247484002&idx1&sn7936818b93f2d9a656d8ed48843272c0不再赘述。 Spri…

谷歌发布了日语版的 Gemma2 模型——gemma-2-2b-jpn-it

Gemma 是一系列同类最佳的开放式模型&#xff0c;其灵感和技术源自 Gemini 系列模型。 它们是具有开放权重的文本到文本、纯解码器大型语言模型。 Gemma 模型非常适合各种文本生成任务&#xff0c;包括问题解答、摘要和推理。 Gemma-2-JPN 是一个针对日语文本进行微调的 Gemma…

详细分析Spring Framework中 @ConditionalOnProperty的基本知识(附Demo)

目录 前言1. 基本知识2. Demo 前言 基本的Java知识推荐阅读&#xff1a; java框架 零基础从入门到精通的学习路线 附开源项目面经等&#xff08;超全&#xff09;【Java项目】实战CRUD的功能整理&#xff08;持续更新&#xff09; 从实战中学习启发 1. 基本知识 Conditiona…

20分钟写一个链表

目录 前言1.带头结点的循环双链表1.1 链表的分类、线性表的对比1.2 双链表基本操作代码实现1.2.1 初始化1.2.2 销毁、打印链表 总结 前言 有一个学长在面试的时候被问到这样一个问题&#xff0c;“你可以用20分钟写一个链表吗&#xff1f;”学长第一反应是&#xff0c;至少要一…

BFS解决多源最短路问题_01矩阵_C++【含多源最短路问题介绍+dist数组介绍】

BFS解决多源最短路问题_01矩阵_C 0. 多源最短路问题介绍1. 题目解析算法分析2. 代码实现 0. 多源最短路问题介绍 如图&#xff0c;红色是出发点&#xff0c;蓝色是终点。以前我们做的题中&#xff0c;出发点只有一个&#xff0c;所谓多源的意思就是&#xff0c;出发点有多个&am…

KubeSphere中集成ApiSix

一、Apache APISIX 介绍 Apache APISIX 是一款开源的高性能、动态云原生网关&#xff0c;由深圳支流科技有限公司于 2019 年捐赠给 Apache 基金会&#xff0c;当前已经成为 Apache 基金会的顶级开源项目&#xff0c;也是 GitHub 上最活跃的网关项目。Apache APISIX 当前已经覆盖…

✨ComfyUI workflow加密工具节点ComfyUI_CryptoCat

✨背景 玩comfyui的朋友都了解&#xff0c;工作流workflow是一种很重要的资产&#xff0c;可以通过workflow把一系列的处理工作组织起来&#xff0c;提升工作效率&#xff0c;甚至分享生成的图片就可以还原整个的工作流&#xff0c;对于分享传播是个好事情&#xff0c;但是对于…

8位单片机与32位单片机

8位单片机与32位单片机 8位与32位指的是什么 单片机的8位或32位说的是什么呢&#xff1f;要搞懂这个问题&#xff0c;首先要搞明白8位或32位说的是单片机上的哪一个部件。 这是单片机的内部框图。单片机内部由这么多部件构成&#xff0c;并不单单是一个CPU&#xff0c;它内部…

微软推出针对个人的 “AI伴侣” Copilot 会根据用户的行为模式、习惯自动进化

微软推出了为每个人提供的“AI伴侣”Copilot&#xff0c;它不仅能够理解用户的需求&#xff0c;还能根据用户的日常习惯和偏好进行适应和进化。帮助处理各种任务和复杂的日常生活场景。 它能够根据用户的生活背景提供帮助和建议&#xff0c;保护用户的隐私和数据安全。Copilot…

【Canvas与色彩】十六等分多彩隔断圆环

【成图】 【代码】 <!DOCTYPE html> <html lang"utf-8"> <meta http-equiv"Content-Type" content"text/html; charsetutf-8"/> <head><title>隔断圆环Draft5十六等分多彩</title><style type"text…

BFS解决FloodFill算法_被围绕的区域_C++

BFS解决FloodFill算法_被围绕的区域_C 1. 题目描述2. 算法分析3. 代码实现 1. 题目描述 leetcode链接&#xff1a;https://leetcode.cn/problems/surrounded-regions/description/ 给你一个m x n的矩阵board&#xff0c;由若干字符X和O组成&#xff0c;捕获 所有 被围绕的区域…

数据结构 ——— 单链表oj题:链表的回文结构

目录 题目要求 手搓简易单链表 代码实现 题目要求 对于一个单链表&#xff0c;设计一个时间复杂度为O(N)&#xff0c;空间复杂度为O(1)的算法&#xff0c;判断其是否为回文结构&#xff0c;给定一个链表的头指针 head&#xff0c;返回一个 bool 值&#xff0c;代表其是否为…

矩阵式键盘接口设计(用单片机读取4x4矩阵式键盘的键号,并将其显示在数码管上)(Proteus 与Keil uVision联合仿真)

一、实验原理 1、分析电路中按键状态检测的方法。 矩阵式&#xff08;也称行列式&#xff09;键盘用于按键数目较多的场合&#xff0c;由行线和列线组成&#xff0c;按键位于行、列交叉点上&#xff0c;见图5-26&#xff0c;一个44的行、列结构可以构成一个16个按键的键盘&…

FastAPI框架使用枚举来型来限定参数、FastApi框架隐藏没多大意义的Schemes模型部分内容以及常见的WSGI服务器Gunicorn、uWSGI了解

一、FastAPI框架使用枚举来型来限定参数 FastAPI框架验证时&#xff0c;有时需要通过枚举的方式来限定参数只能为某几个值中的一个&#xff0c;这时就可以使用FastAPI框架的枚举类型Enum了。publish:December 23, 2020 -Wednesday 代码如下&#xff1a; #引入Enum模块 from fa…