【springsecurity oauth2授权中心】jwt令牌更换成自省令牌 OpaqueToken P4

news2025/4/25 21:34:28

前言

前面实现了授权中心授权,客户端拿到access_token后就能请求资源服务器接口

权限的校验都是在资源服务器上进行的,授权服务器颁发的access_token有限期是2小时,也就是说在2小时之内,不管授权服务器那边用户的权限如何变更都不会影响到资源服务器上的资源请求。

这篇来解决这个问题,让客户端对资源服务器的每次请求都要去问问授权服务器access_token是否还有效,有效的话资源服务器才能通过

授权服务器

在 application.yml 里的 grant-types 后面添加一个 client_credentials

# 之前
oauth2:
  client:
    #...
    grant-types: authorization_code,refresh_token
    
# 修改后
oauth2:
  client:
    #...
    grant-types: authorization_code,refresh_token,client_credentials

配置类 AuthorizationServerConfig 里将 OAuth2TokenCustomizer 由 JwtEncodingContext 改成 OAuth2TokenClaimsContext

//之前
    //    @Bean
//    public OAuth2TokenCustomizer<JwtEncodingContext> jwtCustomizer() {
//        return context -> {
//            if (context.getTokenType().getValue().equals("access_token")) {
//                Collection<? extends GrantedAuthority> authorities = context.getPrincipal().getAuthorities();
//                List<String> authorityNames = authorities.stream()
//                        .map(GrantedAuthority::getAuthority)
//                        .collect(Collectors.toList());
//                context.getClaims().claim("authorities", authorityNames);
//            }
//        };
//    }

//修改后
@Bean
    public OAuth2TokenCustomizer<OAuth2TokenClaimsContext> tokenCustomizer() {
        return context -> {
            if (context.getTokenType().getValue().equals("access_token")) {
                // 从用户详情中提取权限
                Collection<? extends GrantedAuthority> authorities =
                        context.getPrincipal().getAuthorities();

                // 将权限列表放入令牌声明
                context.getClaims().claim(
                        "authorities",
                        authorities.stream()
                                .map(GrantedAuthority::getAuthority)
                                .collect(Collectors.toList())
                );
            }
        };
    }

资源服务器

添加一个依赖

<dependency>
            <groupId>com.nimbusds</groupId>
            <artifactId>oauth2-oidc-sdk</artifactId>
            <version>11.23.1</version>
            <scope>runtime</scope>
        </dependency>

创建一个自省令牌解析器 CustomAuthoritiesOpaqueTokenIntrospector

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.oauth2.core.DefaultOAuth2AuthenticatedPrincipal;
import org.springframework.security.oauth2.core.OAuth2AuthenticatedPrincipal;
import org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class CustomAuthoritiesOpaqueTokenIntrospector implements OpaqueTokenIntrospector {

    private final OpaqueTokenIntrospector delegate;

    public CustomAuthoritiesOpaqueTokenIntrospector(OpaqueTokenIntrospector delegate) {
        this.delegate = delegate;
    }

    @Override
    public OAuth2AuthenticatedPrincipal introspect(String token) {
        OAuth2AuthenticatedPrincipal principal = this.delegate.introspect(token);

        Map<String, Object> claims = principal.getAttributes();
        List<String> authorities = (List<String>) claims.get("authorities");

        if (authorities == null) throw new SecurityException("没有权限");
        Collection<GrantedAuthority> grantedAuthorities = authorities.stream()
                .map(auth -> new SimpleGrantedAuthority(auth)) // 直接使用权限名,不加 SCOPE_ 前缀
                .collect(Collectors.toList());

        return new DefaultOAuth2AuthenticatedPrincipal(claims, grantedAuthorities);
    }
}

修改 ResourceServerConfig 配置类

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
                .authorizeHttpRequests(authorize -> authorize
                        .anyRequest().authenticated()
                )
                .oauth2ResourceServer(oauth2 -> oauth2
                                // 注释掉jwt
//                        .jwt(jwt -> jwt
//                                .jwkSetUri("http://localhost:9000/oauth2/jwks")
//                                .jwtAuthenticationConverter(jwtAuthenticationConverter()) // 使用自定义转换器
//                        )
                                // 添加上 opaque
                                .opaqueToken(opaque -> opaque
//                                        .introspectionUri("http://localhost:9000/oauth2/introspect")
//                                        .introspectionClientCredentials("client", "secret")
                                                .introspector(customOpaqueTokenIntrospector())
                                )
                );
        return http.build();
    }
    // jwt权限转换器,这里用不到了注释掉
//    @Bean
//    public JwtAuthenticationConverter jwtAuthenticationConverter() {
//        JwtGrantedAuthoritiesConverter grantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
//        grantedAuthoritiesConverter.setAuthoritiesClaimName("authorities"); // 指定JWT中权限字段名
//        grantedAuthoritiesConverter.setAuthorityPrefix(""); // 去掉默认的"SCOPE_"前缀
//
//        JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();
//        jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(grantedAuthoritiesConverter);
//        return jwtAuthenticationConverter;
//    }

配置授权服务器的请求 /oauth2/introspect 是内置的,不要修改

    @Bean
    public OpaqueTokenIntrospector customOpaqueTokenIntrospector() {
        // 1. 创建默认的 Introspector(连接授权服务器)
        OpaqueTokenIntrospector delegate = new NimbusOpaqueTokenIntrospector(
                "http://localhost:9000/oauth2/introspect",
                "client", // client_id
                "secret"  // client_secret 与授权服务器保持一致
        );

        // 2. 包装成自定义实现
        return new CustomAuthoritiesOpaqueTokenIntrospector(delegate);
    }

测试

拿code换access_token的流程跟前面是一样的,下面用access_token请求一下资源服务器的接口看看

/api/hello 接口因为有权限请求成功
在这里插入图片描述
请求 /api/hello 接口时,资源服务器日志
在这里插入图片描述
授权服务器日志
在这里插入图片描述

总结

  • jwt方式简单直接,对授权服务器压力比较小,一次授权能用很长时间,期间授权服务器处于闲置状态。适合内部系统且用户权限不经常变动的系统
  • 自省令牌稍微麻烦点,对授权服务器压力大,每次请求都需要授权服务器校验,适合用户权限经常变动的系统。

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

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

相关文章

诱骗协议芯片支持PD2.0/3.0/3.1/PPS协议,支持使用一个Type-C与电脑传输数据和快充取电功能

快充是由充电器端的充电协议和设备端的取电协议进行握手通讯进行协议识别来完成的&#xff0c;当充电器端的充电协议和设备端的取电协议握手成功后&#xff0c;设备会向充电器发送电压请求&#xff0c;充电器会根据设备的需求发送合适的电压给设备快速供电。 设备如何选择快充…

变量在template里不好使,在setup好使?

问题&#xff1a; 自定义的一个函数 &#xff0c;import导入后 setup里面使用正常 &#xff0c;在template里面说未定义 作用域问题 在 Vue 的模板语法中&#xff0c;模板&#xff08;template &#xff09;里能直接访问的是组件实例上暴露的属性和方法。从代码看&#xff0c…

OpenCV 图形API(53)颜色空间转换-----将 RGB 图像转换为灰度图像函数RGB2Gray()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 将图像从 RGB 色彩空间转换为灰度。 R、G 和 B 通道值的常规范围是 0 到 255。生成的灰度值计算方式如下&#xff1a; dst ( I ) 0.299 ∗ src…

Trae+DeepSeek学习Python开发MVC框架程序笔记(四):使用sqlite存储查询并验证用户名和密码

继续通过Trae向DeepSeek发问并修改程序&#xff0c;实现程序运行时生成数据库&#xff0c;用户在系统登录页面输入用户名和密码后&#xff0c;控制器通过模型查询用户数据库表来验证用户名和密码&#xff0c;验证通过后显示登录成功页面&#xff0c;验证失败则显示登录失败页面…

超详细mac上用nvm安装node环境,配置npm

一、安装NVM 打开终端&#xff0c;运行以下命令来安装NVM&#xff1a; curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.5/install.sh | bash 然后就会出现如下代码&#xff1a; > Profile not found. Tried ~/.bashrc, ~/.bash_profile, ~/.zprofile, ~/.…

hi3516cv610构建音频sample工程代码步骤

hi3516cv610构建音频sample工程代码步骤 sdk版本&#xff1a;Hi3516CV610_SDK_V1.0.1.0 硬件&#xff1a;非es8388 工程代码&#xff1a; 通过网盘分享的文件&#xff1a;audio_easy.zip 链接: https://pan.baidu.com/s/1gx61S_F3-pf6hPyfbGaRXg 提取码: 4gbg --来自百度网盘…

12.QT-Combo Box|Spin Box|模拟点餐|从文件中加载选项|调整点餐份数(C++)

Combo Box QComboBox 表⽰下拉框 核⼼属性 属性说明currentText当前选中的⽂本currentIndex当前选中的条⽬下标.从0开始计算.如果当前没有条⽬被选中,值为-1editable是否允许修改设为true时, QComboBox 的⾏为就⾮常接近 QLineEdit ,也可以 设置 validatoriconSize下拉框图标…

UML 顺序图:电子图书馆管理系统的交互之道

目录 一、初识 UML 顺序图 二、电子图书馆管理系统顺序图解析 &#xff08;一&#xff09;借阅流程 &#xff08;二&#xff09;归还流程 三、顺序图绘画 四、顺序图的优势与价值 五、总结 UML 顺序图是描绘系统组件交互的有力工具。顺序图直观展示消息传递顺序与对象协…

访问者模式:分离数据结构与操作的设计模式

访问者模式&#xff1a;分离数据结构与操作的设计模式 一、模式核心&#xff1a;将操作从数据结构中分离&#xff0c;支持动态添加新操作 在软件开发中&#xff0c;当数据结构&#xff08;如树、集合&#xff09;中的元素类型固定&#xff0c;但需要频繁添加新的操作&#xf…

【AI训练环境搭建】在IDE(Pycharm或VSCode)上使用WSL2+Ubuntu22.04+Conda+Tensorflow+GPU进行机器学习训练

本次实践将在IDE&#xff08;Pycharm或VSCode&#xff09;上使用WSL2Ubuntu22.04TensorflowGPU进行机器学习训练。基本原理是在IDE中拉起WSL2中的Python解释器&#xff0c;并运行Python程序。要运行CondaTensorflowGPU你可能需要进行以下准备工作。 1. 此示例中将使用一个mnis…

Leetcode19(亚马逊真题):删除链表的倒是第N个节点

题目分析 删除节点关键&#xff1a;找到被删节点的前一个节点&#xff0c;指针指向 虚拟头节点&#xff0c;方便删除头结点&#xff0c;形成统一操作 为啥要让快指针先行&#xff1f; 我认为更好懂的一种解释&#xff1a;快指针先行n步&#xff0c;这样快慢指针之间形成了一…

Hadoop+Spark 笔记 2025/4/21

读书笔记 定义 1. 大数据&#xff08;Big Data&#xff09; - 指传统数据处理工具难以处理的海量、高速、多样的数据集合&#xff0c;通常具备3V特性&#xff08;Volume体量大、Velocity速度快、Variety多样性&#xff09;。扩展后还包括Veracity&#xff08;真实性&#x…

Redis从入门到实战基础篇

前言&#xff1a;Redis的安装包含在Redis从入门到实战先导篇中&#xff0c;需要的可移步至此节 目录 1.Redis简单介绍 2.初始Redis 2.1.认识NoSQL 2.2.认识Redis 2.3.安装Redis 3.Redis常见命令 3.1 Redis数据结构 3.2 通用命令 3.3 String命令 3.4 Key的层级结构 3…

Java虚拟机(JVM)家族发展史及版本对比

Java虚拟机&#xff08;JVM&#xff09;家族发展史及版本对比 一、JVM家族发展史 1. 早期阶段&#xff08;1996-2000&#xff09; Classic VM&#xff08;Java 1.0-1.1&#xff09;&#xff1a; 厂商&#xff1a;Sun Microsystems&#xff08;Oracle前身&#xff09;。特点&…

【学习笔记】Cadence电子设计全流程(三)Capture CIS 原理图绘制(下)

【学习笔记】Cadence电子设计全流程&#xff08;三&#xff09;Capture CIS 原理图绘制&#xff08;下&#xff09; 3.16 原理图中元件的编辑与更新3.17 原理图元件跳转与查找3.18 原理图常见错误设置于编译检查3.19 低版本原理图文件输出3.20 原理图文件的锁定与解锁3.21 Orca…

OpenCV 图形API(54)颜色空间转换-----将图像从 RGB 色彩空间转换到 HSV色彩空间RGB2HSV()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 将图像从 RGB 色彩空间转换为 HSV。该函数将输入图像从 RGB 色彩空间转换到 HSV。R、G 和 B 通道值的常规范围是 0 到 255。 输出图像必须是 8 位…

JavaWeb学习打卡-Day1-分层解耦、Spring IOC、DI

三层架构 Controller&#xff08;控制层&#xff09;&#xff1a;接收前端发送的请求&#xff0c;对请求进行处理&#xff0c;并响应数据。Service&#xff08;业务逻辑层&#xff09;&#xff1a;处理具体的业务逻辑。DAO&#xff08;数据访问层/持久层&#xff09;&#xff…

基于 Electron、Vue3 和 TypeScript 的辅助创作工具全链路开发方案:涵盖画布系统到数据持久化的完整实现

基于 Electron、Vue3 和 TypeScript 的辅助创作工具全链路开发方案&#xff1a;涵盖画布系统到数据持久化的完整实现 引言 在数字内容创作领域&#xff0c;高效的辅助工具是连接创意与实现的关键桥梁。创作者需要一款集可视化画布、节点关系管理、数据持久化于一体的专业工具&…

[Java · 铢积寸累] 数据结构 — 数组类型 - 增 删 改 查

&#x1f31f; 想系统化学习 Java 编程&#xff1f;看看这个&#xff1a;[编程基础] Java 学习手册 在上一章中我们介绍了如何声明与创建数组&#xff0c;还介绍了数组的基本使用方式。本章我们将在上一章的基础上&#xff0c;拓展数组的使用方式&#xff08;可能会涉及一些思…

前端笔记-Axios

Axios学习目标 Axios与API交互1、Axios配置与使用2、请求/响应拦截器3、API设计模式&#xff08;了解RESTful风格即可&#xff09; 学习参考&#xff1a;起步 | Axios中文文档 | Axios中文网 什么是Axios Axios 是一个基于 Promise 的现代化 HTTP 客户端库&#xff0c;专…