Spring Security—OAuth 2.0 资源服务器的多租户
一、同时支持JWT和Opaque Token
在某些情况下,你可能需要访问两种令牌。例如,你可能支持一个以上的租户,其中一个租户发出JWT,另一个发出 opaque token。
如果这个决定必须在请求时做出,那么你可以使用 AuthenticationManagerResolver 来实现它,就像这样。
-
Java
@Bean
AuthenticationManagerResolver<HttpServletRequest> tokenAuthenticationManagerResolver(JwtDecoder jwtDecoder, OpaqueTokenIntrospector opaqueTokenIntrospector) {AuthenticationManager jwt = new ProviderManager(new JwtAuthenticationProvider(jwtDecoder));AuthenticationManager opaqueToken = new ProviderManager(new OpaqueTokenAuthenticationProvider(opaqueTokenIntrospector));return (request) -> useJwt(request) ? jwt : opaqueToken;
}
useJwt(HttpServletRequest) 的实现很可能取决于自定义的请求,如路径。 |
然后在DSL中指定这个 AuthenticationManagerResolver。
Authentication Manager Resolver
-
Java
http.authorizeHttpRequests(authorize -> authorize.anyRequest().authenticated()).oauth2ResourceServer(oauth2 -> oauth2.authenticationManagerResolver(this.tokenAuthenticationManagerResolver));
二、多租户
当有多种验证 bearer token 的策略时,一个资源服务器被认为是多租户的,其关键是一些租户标识符。
例如,你的资源服务器可能接受来自两个不同授权服务器的 bearer token。或者,你的授权服务器可以代表多个发行者。
在每一种情况下,都有两件事需要做,以及与你选择如何做有关的权衡。
-
解析租户。
-
传递租户。
1、通过 Claim 解析租户
区分租户的一个方法是通过 issuer claim。由于 issuer claim 伴随着签名的JWTs,这可以通过 JwtIssuerAuthenticationManagerResolver 来完成,像这样。
Multi-tenancy Tenant by JWT Claim
-
Java
JwtIssuerAuthenticationManagerResolver authenticationManagerResolver = new JwtIssuerAuthenticationManagerResolver("https://idp.example.org/issuerOne", "https://idp.example.org/issuerTwo");http.authorizeHttpRequests(authorize -> authorize.anyRequest().authenticated()).oauth2ResourceServer(oauth2 -> oauth2.authenticationManagerResolver(authenticationManagerResolver));
这很好,因为发行者端点的加载是延迟的。事实上,相应的 JwtAuthenticationProvider 只有在发送第一个请求的时候才会被实例化。这使得应用程序的启动与这些授权服务器的启动和可用性无关。
2.1、动态租户
当然,你可能不想在每次添加新租户时都重启应用程序。在这种情况下,你可以用一个 AuthenticationManager 实例库来配置 JwtIssuerAuthenticationManagerResolver,你可以在运行时编辑它,就像这样。
-
Java
private void addManager(Map<String, AuthenticationManager> authenticationManagers, String issuer) {JwtAuthenticationProvider authenticationProvider = new JwtAuthenticationProvider(JwtDecoders.fromIssuerLocation(issuer));authenticationManagers.put(issuer, authenticationProvider::authenticate);
}// ...JwtIssuerAuthenticationManagerResolver authenticationManagerResolver =new JwtIssuerAuthenticationManagerResolver(authenticationManagers::get);http.authorizeHttpRequests(authorize -> authorize.anyRequest().authenticated()).oauth2ResourceServer(oauth2 -> oauth2.authenticationManagerResolver(authenticationManagerResolver));
在这种情况下,你构建 JwtIssuerAuthenticationManagerResolver,其策略是获取给定发行者的 AuthenticationManager。这种方法允许我们在运行时从资源库(在片段中显示为 Map)中添加和删除元素。
简单地采用任何发行者并从中构建一个 AuthenticationManager 是不安全的。发行者应该是代码可以从可信的来源(如允许的发行者列表)中验证的。 |
2.2 只对 Claim 进行一次解析
你可能已经注意到,这种策略虽然简单,但也有代价,那就是JWT被 AuthenticationManagerResolver 解析了一次,然后又被 JwtDecoder 在后来的请求中再次解析。
这种额外的解析可以通过使用 Nimbus 的 JWTClaimsSetAwareJWSKeySelector 直接配置 JwtDecoder 来缓解。
-
Java
@Component
public class TenantJWSKeySelectorimplements JWTClaimsSetAwareJWSKeySelector<SecurityContext> {private final TenantRepository tenants; private final Map<String, JWSKeySelector<SecurityContext>> selectors = new ConcurrentHashMap<>(); public TenantJWSKeySelector(TenantRepository tenants) {this.tenants = tenants;}@Overridepublic List<? extends Key> selectKeys(JWSHeader jwsHeader, JWTClaimsSet jwtClaimsSet, SecurityContext securityContext)throws KeySourceException {return this.selectors.computeIfAbsent(toTenant(jwtClaimsSet), this::fromTenant).selectJWSKeys(jwsHeader, securityContext);}private String toTenant(JWTClaimsSet claimSet) {return (String) claimSet.getClaim("iss");}private JWSKeySelector<SecurityContext> fromTenant(String tenant) {return Optional.ofNullable(this.tenants.findById(tenant)) .map(t -> t.getAttrbute("jwks_uri")).map(this::fromUri).orElseThrow(() -> new IllegalArgumentException("unknown tenant"));}private JWSKeySelector<SecurityContext> fromUri(String uri) {try {return JWSAlgorithmFamilyJWSKeySelector.fromJWKSetURL(new URL(uri)); } catch (Exception ex) {throw new IllegalArgumentException(ex);}}
}
| 一个假设的租户信息来源 |
JWKKeySelector 的缓存,以租户标识符(ID)为key。 |
| 查询租户比简单地计算JWK Set端点更安全—查询作为一个允许租户的列表 |
通过从JWK Set端点回来的key类型创建一个 JWSKeySelector — 这里的延迟查找意味着你不需要在启动时配置所有租户 |
上述密钥选择器是许多密钥选择器的组合。它根据JWT中的 iss claim 来选择使用哪个key选择器。
| 要使用这种方法,请确保授权服务器被配置为包括 claim 集作为令牌签名的一部分。如果不这样做,你就不能保证 issuer 没有被坏行为者改变。 |
接下来,我们可以构建一个 JWTProcessor。
-
Java
@Bean
JWTProcessor jwtProcessor(JWTClaimSetJWSKeySelector keySelector) {ConfigurableJWTProcessor<SecurityContext> jwtProcessor =new DefaultJWTProcessor();jwtProcessor.setJWTClaimSetJWSKeySelector(keySelector);return jwtProcessor;
}
正如你已经看到的,将租户意识下移到这个层次的代价是更多的配置。我们只是多了一点。
接下来,我们仍然要确保你正在验证 issuer。但是,由于每个JWT的 issuer 可能是不同的,那么你也需要一个租户感知的验证器。
-
Java
@Component
public class TenantJwtIssuerValidator implements OAuth2TokenValidator<Jwt> {private final TenantRepository tenants;private final Map<String, JwtIssuerValidator> validators = new ConcurrentHashMap<>();public TenantJwtIssuerValidator(TenantRepository tenants) {this.tenants = tenants;}@Overridepublic OAuth2TokenValidatorResult validate(Jwt token) {return this.validators.computeIfAbsent(toTenant(token), this::fromTenant).validate(token);}private String toTenant(Jwt jwt) {return jwt.getIssuer();}private JwtIssuerValidator fromTenant(String tenant) {return Optional.ofNullable(this.tenants.findById(tenant)).map(t -> t.getAttribute("issuer")).map(JwtIssuerValidator::new).orElseThrow(() -> new IllegalArgumentException("unknown tenant"));}
}
现在我们有了一个租户识别处理器和一个租户识别验证器,我们可以继续创建我们的 JwtDecoder。
-
Java
@Bean
JwtDecoder jwtDecoder(JWTProcessor jwtProcessor, OAuth2TokenValidator<Jwt> jwtValidator) {NimbusJwtDecoder decoder = new NimbusJwtDecoder(processor);OAuth2TokenValidator<Jwt> validator = new DelegatingOAuth2TokenValidator<>(JwtValidators.createDefault(), jwtValidator);decoder.setJwtValidator(validator);return decoder;
}
我们已经完成了关于解析租户的讨论。
如果你选择通过JWT请求以外的方式来解析租户,那么你需要确保你以同样的方式来解决你的下游资源服务器。例如,如果你是通过子域进行解析,你可能需要使用相同的子域来解决下游资源服务器。
相关文章:
Spring Security—OAuth 2.0 资源服务器的多租户
一、同时支持JWT和Opaque Token 在某些情况下,你可能需要访问两种令牌。例如,你可能支持一个以上的租户,其中一个租户发出JWT,另一个发出 opaque token。 如果这个决定必须在请求时做出,那么你可以使用 Authenticati…...
VB.NET—窗体引起的乌龙事件
目录 前言: 过程: 总结: 升华: 前言: 分享一个VB.NET遇到的一个问题,开始一直没有解决,这个问题阻碍了很长时间,成功的变成我路上的绊脚石,千方百计的想要绕过去,但事与愿违怎么也绕不过去,因为运行不了…...
批量新增报错PSQLException: PreparedStatement can have at most 65,535 parameters.
报错信息: org.postgresql.util.PSQLException: PreparedStatement can have at most 65,535 parameters. Please consider using arrays, or splitting the query in several ones, or using COPY. Given query has 661,068 parameters ; SQL []; PreparedStatemen…...
数仓分层能减少重复计算,为啥能减少?如何减少?这篇文章包懂!
很多时候,看一些数据领域的文章,说到为什么做数据仓库、数据仓库要分层,我们经常会看到一些结论:因为有ABCD…等等理由,比如降低开发成本、减少重复计算等等好处 然后,多数人就记住了ABCD。但是࿰…...
【Linux】基础IO之文件操作(文件fd)——针对被打开的文件
系列文章目录 文章目录 系列文章目录前言浅谈文件的共识 一、 回忆c语言对文件操作的接口1.fopen接口和cwd路径2.fwrite接口和"w","a"方法3.fprintf接口和三个默认打开的输入输出流(文件) 二、过渡到系统,认识…...
什么是超算数据中心
超算数据中心是基于超级计算机或者是大规模的计算集群的数据中心,它具备高性能、高可靠性、高可用性和高扩展性这些特点,能够提供大规模计算、存储和网络服务的功能,在人工智能、科学计算、数据分析等等领域应用比较广泛。 超算数据中心有以下…...
阿里云服务器省钱购买和使用方法(图文详解)
阿里云服务器使用教程包括云服务器购买、云服务器配置选择、云服务器开通端口号、搭建网站所需Web环境、安装网站程序、域名解析到云服务器公网IP地址,最后网站上线全流程,新手站长xinshouzhanzhang.com分享阿里云服务器详细使用教程: 一&am…...
Apache Flink 1.12.0 on Yarn(3.1.1) 所遇到的問題
Apache Flink 1.12.0 on Yarn(3.1.1) 所遇到的問題 新搭建的FLINK集群出现的问题汇总 1.新搭建的Flink集群和Hadoop集群无法正常启动Flink任务 查看这个提交任务的日志无法发现有用的错误信息。 进一步查看yarn日志: 发现只有JobManager的错误日志出现了如下的…...
pandas - 数据分组统计
1.分组统计groupby()函数 对数据进行分组统计,主要适用DataFrame对象的groupby()函数。其功能如下。 (1)根据特定条件,将数据拆分成组 (2)每个组都可以独立应用函数(如求和函数sum()࿰…...
Git简介和安装
一,Git简介 Git 是一个分布式版本控制工具,通常用来对软件开发过程中的源代码文件进行管理。通过Git 仓库来存储和管理这些文件,Git 仓库分为两种: 本地仓库:开发人员自己电脑上的 Git 仓库 远程仓库:远程…...
思维模型 布里丹毛驴效应
本系列文章 主要是 分享 思维模型,涉及各个领域,重在提升认知。犹豫不决是病,得治~ 1 布里丹毛驴效应的应用 1.1 犹豫不决的产品“施乐 914” 20 世纪 60 年代,美国一家名为施乐(Xerox)的公司…...
预处理、编译、汇编、链接
1.预处理 宏替换去注释引入头文件 #之后的语句都是预处理语句, #include<iostream> 将该文件的内容拷贝到现有文件中, 2.编译 3.汇编 4.链接 gcc 基于C/C的编译器 补充说明 gcc命令 使用GNU推出的基于C/C的编译器,是开放源代…...
面试问题?
1.面向对象的特征? 2.开放闭合 3.java中的泛型可以用基本类型吗? 4.重载和重写的区别? 5.string、stringbuffer、stringbuilder? 6.单例模式的实现方式有哪几种? 7.volicate除了保证 8.sy是重量级锁还是轻量级锁ÿ…...
pytorch 笔记:PAD_PACKED_SEQUENCE 和PACK_PADDED_SEQUENCE
1 PACK_PADDED_SEQUENCE 1.0 功能 将填充的序列打包成一个更加紧凑的形式这样RNN、LSTM和GRU等模型可以更高效地处理它们,因为它们可以跳过不必要的计算 1.2 基本使用方法 torch.nn.utils.rnn.pack_padded_sequence(input, lengths, batch_firstFalse, enforce_…...
Ubuntu 创建用户
在ubuntu系统中创建用户,是最基本的操作。与centos7相比,有较大不同。 我们通过案例介绍,讨论用户的创建。 我们知道,在linux中,有三类用户:超级管理员 root 具有完全权限;系统用户 bin sys a…...
华为政企路由器产品集
产品类型产品型号产品说明 maintainProductA821 E_2*10GE/GE/FE(o)8*GE/FE(o)8*GE/FE(e),1*交流电源华为企业云端NetEngine A800 E综合业务一体化接入路由器是华为公司面向云时代推出的一款产品,用于企业快速接入网络,具备易部署、易运维、高性能、高…...
性能测试知多少---了解前端性能
我的上一篇博文中讲到了响应时间,我们在做性能测试时,能过工具可以屏蔽客户端呈现时间,通过局域网的高宽带可以忽略数据传输速度的障碍。这并不是说他们不会对系统造成性能影响。相反,从用户的感受来看,虽然传输速度受…...
Docker-compose容器群集编排管理工具
目录 Docker-compose 1、Docker-compose 的三大概念 2、YAML文件格式及编写注意事项 1)使用 YAML 时需要注意下面事项 2)ymal文件格式 3)json格式 3、Docker Compose配置常用字段 4、Docker-compose的四种重启策略 5、Docker Compose…...
Python 深度学习导入的一些包的说明
Python 深度学习导入的一些包的说明 这段代码导入了一些Python库和模块,并定义了一些数据转换操作。 from future import print_function, division:这是一个Python 2和Python 3兼容性的导入语句。它确保在Python 2中使用Python 3的print函数和除法运算符…...
劲升逻辑与安必快、鹏海运于进博会签署合作协议,助力大湾区外贸高质量发展
新中经贸与投资论坛签约现场 中国上海,2023 年 11 月 6 日——第六届进博会期间,由新加坡工商联合总会主办的新中经贸与投资论坛在上海同期举行。跨境贸易数字化领域的领导者劲升逻辑与安必快科技(深圳)有限公司(简称…...
基于XGBoost与SHAP的分子气味预测:从特征工程到可解释性分析
1. 项目概述与核心价值在香水设计、食品风味工业乃至环境监测领域,一个核心且持久的挑战是:如何从分子的化学结构出发,准确预测其气味?这不仅仅是化学家或调香师的直觉游戏,更是一个复杂的、高维度的模式识别问题。传统…...
从RD、CS到WK:一文讲透SAR主流成像算法的演进与选型实战
从RD、CS到WK:SAR成像算法选型实战指南 当无人机掠过灾区上空,或卫星扫描地球表面时,合成孔径雷达(SAR)正通过电磁波穿透云层和黑暗,将地面信息转化为高分辨率图像。而决定图像质量的关键,在于工…...
基于PIC32的嵌入式MIDI合成器:从波表合成到硬件实现
1. 项目概述:一个基于嵌入式微控制器的MIDI声音合成器如果你对电子音乐制作、嵌入式开发,或者DIY硬件合成器感兴趣,那么“REMI Synth”这个项目绝对值得你花时间深入了解。它本质上是一个数字单音MIDI控制的声音合成器,核心是一块…...
GEO优化可以覆盖哪些搜索平台
这是一个非常现实的问题。企业投放资源做GEO,当然希望覆盖面越广越好。那么GEO优化到底能覆盖哪些平台?覆盖到什么程度?不同平台的GEO逻辑有什么差异?GEO平台覆盖的三个层级第一层级:通用大模型AI平台(核心…...
AutoWall终极指南:如何在Windows上轻松设置炫酷动态壁纸
AutoWall终极指南:如何在Windows上轻松设置炫酷动态壁纸 【免费下载链接】AutoWall 🌌 Live wallpapers on Windows 7/8/10/11 using open-source wallpaper engine 项目地址: https://gitcode.com/gh_mirrors/au/AutoWall 厌倦了千篇一律的静态桌…...
WarcraftHelper:让魔兽争霸3在现代电脑上完美运行的关键插件
WarcraftHelper:让魔兽争霸3在现代电脑上完美运行的关键插件 【免费下载链接】WarcraftHelper Warcraft III Helper , support 1.20e, 1.24e, 1.26a, 1.27a, 1.27b 项目地址: https://gitcode.com/gh_mirrors/wa/WarcraftHelper 你是否还在为《魔兽争霸3》这…...
反向海淘站点常见配置故障复盘与数据一致性优化方案
摘要反向海淘独立站运行过程中,容易出现价格换算异常、页面语种错乱、商品同步失败、订单状态停滞、运费计算偏差等问题。多数故障并非系统底层缺陷,而是配置逻辑理解偏差、数据规范不统一引发。本文结合实际运维场景,汇总高频故障成因&#…...
如何用500KB工具完全替代AWCC:AlienFX Tools终极指南
如何用500KB工具完全替代AWCC:AlienFX Tools终极指南 【免费下载链接】alienfx-tools Alienware systems lights, fans, and power control tools and apps 项目地址: https://gitcode.com/gh_mirrors/al/alienfx-tools 你是否厌倦了Alienware Command Cente…...
终极空洞骑士模组管理器 Lumafly:跨平台一键安装与智能依赖管理指南
终极空洞骑士模组管理器 Lumafly:跨平台一键安装与智能依赖管理指南 【免费下载链接】Lumafly A cross platform mod manager for Hollow Knight written in Avalonia. 项目地址: https://gitcode.com/gh_mirrors/lu/Lumafly Lumafly 是一款基于 Avalonia 框…...
用Playwright自动化测试工具,5分钟搞定网站短信验证码接口的批量测试
用Playwright实现短信验证码接口的自动化测试实战指南短信验证码作为现代Web应用的核心安全组件,其稳定性和防护能力直接影响用户体验和系统安全。根据2023年DevOps状态报告,超过60%的线上身份验证故障源于短信服务接口的异常。本文将带你用Playwright这…...
