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

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

前言

前面实现了授权中心授权,客户端拿到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);
//            }
//        };
//    }//修改后
@Beanpublic 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;}@Overridepublic 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 配置类

    @Beanpublic 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 是内置的,不要修改

    @Beanpublic 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.xdnf.cn/news/1261.html

相关文章:

  • 西门子PLC S7-1200按钮控制灯实例
  • day4-小白学习JAVA---开发软件_Scanner键盘录入_Random随机数_流程控制语句
  • 基于龙芯 2K1000处理器和复旦微 FPGA K7 的全国产RapidIO 解决方案研究
  • 【Pytorch 中的扩散模型】去噪扩散概率模型(DDPM)的实现
  • ProxySQL性能调优案例
  • 星光璀璨,跨界共鸣——李炳辰亮相 第十五届北影节嘉年华“音乐之旅”
  • [Java · 铢积寸累] 可变参数
  • Win10 关闭自动更新、关闭自动更新并重启
  • 实践项目开发-hbmV4V20250407-跨平台开发框架深度解析与VSCode一站式开发实践
  • 重装系统后的自用包
  • MulanPSL-1.0开源协议
  • PaddlePaddle线性回归详解:从模型定义到加载,掌握深度学习基础
  • 状态空间模型(State‐Space Model)、传递函数和极点
  • React项目添加react-quill富文本编辑器,遇到的问题,比如hr标签丢失
  • 文件操作和IO(上)
  • Towards Multi-Domain Learning for Generalizable Video Anomaly Detection
  • 一页概览:EMC Avamar备份方案
  • C++初阶——string的使用(上)
  • Tomcat启动闪退是为什么?
  • 第6次课 贪心算法 A
  • Electron使用WebAssembly实现CRC-32 原理校验
  • 前端路由 ( 1 ) | history 原理
  • Hyper-V 管理工具
  • Java队列(Queue)核心操作与最佳实践:深入解析与面试指南
  • AI+直播电商:短视频商城APP开发如何实现智能化推荐?
  • Varjo-XR3在UE5中,头显中间有一个方块一直显示
  • Java Set/List 知识点 Java面试 基础面试题
  • 无人设备遥控器之远程操控系统篇
  • 数据结构-队列
  • Redis 共享和独立集群两种模式各自的优缺点是什么?