SpringBoot3集成Oauth2——1(/oauth2/token方法的升级踩坑)

备注:本文适用于你在SpringBoot2.7以前集成过oauth2,并且项目已经正式投入使用的情况,否则,我建议你直接学习或者找资料学习最新的oauth2集成,就不要纠结于老版本的oauth2。

原因:Spring Security 5.x和Spring Security6.x,我个人认为,你可以理解为两套不同的框架,他们仅仅只是名字差不多而已,升级难度在于,旧系统的登录认证已经在使用了,尤其是已经介入很多子系统时,这时候需升级需要适配原来的认证,不然会导致子系统需要重新单点登录。

Spring Security 5.x → 6.x:
弃用旧 API:spring-security-oauth2-autoconfigure 被移除,取而代之的是更模块化的组件(如 spring-boot-starter-oauth2-client)。
新认证架构:基于 SecurityFilterChain 和 AuthenticationProvider 的声明式配置取代了旧的 WebSecurityConfigurerAdapter。

本文部分内容参考:https://blog.csdn.net/gandilong 写的SpringBoot+SpringSecurity OAuth2 认证服务搭建实战 (二)

文章目录

  • 1快速demo 授权服务器
    • 1.1依赖
    • 1.2AuthorizationServerConfig
    • 1.3SecurityConfig
    • 1.4验证
  • 2老版本/oauth/token
  • 3问题:认证接口变了
  • 4新版本/oauth2/token
    • 4.1定位/oauth2/token

1快速demo 授权服务器

1.1依赖

springBoot版本

   <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.4.4</version><relativePath/> <!-- lookup parent from repository --></parent>
		<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-oauth2-authorization-server</artifactId></dependency>

通过查看依赖,发现,SpringBoot3.4.4引用如下依赖

<dependency><groupId>org.springframework.security</groupId><artifactId>spring-security-oauth2-authorization-server</artifactId><version>1.3.0</version><scope>compile</scope></dependency>

1.2AuthorizationServerConfig

import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.UUID;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
import org.springframework.security.oauth2.core.oidc.OidcScopes;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.jwt.JwtEncoder;
import org.springframework.security.oauth2.jwt.NimbusJwtEncoder;
import org.springframework.security.oauth2.server.authorization.client.InMemoryRegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration;
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OAuth2AuthorizationServerConfigurer;
import org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings;
import org.springframework.security.oauth2.server.authorization.web.OAuth2ClientAuthenticationFilter;
import org.springframework.security.oauth2.server.authorization.web.OAuth2TokenEndpointFilter;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.jwk.RSAKey;
import com.nimbusds.jose.jwk.source.ImmutableJWKSet;
import com.nimbusds.jose.jwk.source.JWKSource;
import com.nimbusds.jose.proc.SecurityContext;@Configuration
@Import(OAuth2AuthorizationServerConfiguration.class)
public class AuthorizationServerConfig {OAuth2TokenEndpointFilter  OAuth2TokenEndpointFilter ;OAuth2AuthorizationServerConfigurer  OAuth2AuthorizationServerConfigurer;OAuth2ClientAuthenticationFilter  OAuth2ClientAuthenticationFilter ;@Beanpublic PasswordEncoder passwordEncoder() throws NoSuchAlgorithmException {return new BCryptPasswordEncoder(12,SecureRandom.getInstanceStrong());}/*** 提供登录页面用户名密码的认证* @return*/@Beanpublic UserDetailsService userDetailsService(PasswordEncoder passwdEncoder) {UserDetails user= User.builder().username("user")//.password(passwdEncoder.encode("123")) // 使用 {noop} 前缀表示密码不会被编码.password("{noop}123") // 使用 {noop} 前缀表示密码不会被编码.accountExpired(false).credentialsExpired(false).accountLocked(false).authorities("ROLE_USER") // 用户的权限.build();return new InMemoryUserDetailsManager(user);}/*** 应用注册仓库* @return*/@Beanpublic RegisteredClientRepository registeredClientRepository(PasswordEncoder passwdEncoder) {RegisteredClient oidcClient = RegisteredClient.withId(UUID.randomUUID().toString()).clientId("clientid").clientSecret(passwdEncoder.encode("client_secret"))如果是CLIENT_SECRET_POST才会用到.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC).clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_POST).clientAuthenticationMethod(ClientAuthenticationMethod.NONE).authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE).authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS).authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN).redirectUri("http://localhost:8080/login/oauth2/code/clientid").postLogoutRedirectUri("http://localhost:8080/").scope(OidcScopes.OPENID).scope(OidcScopes.PROFILE).build();return new InMemoryRegisteredClientRepository(oidcClient);}/*** 生成jwk,用在jwt编码和jwt解码器上* @return*/@Beanpublic JWKSource<SecurityContext> jwkSource() {KeyPair keyPair = generateRsaKey();RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();RSAKey rsaKey = new RSAKey.Builder(publicKey).privateKey(privateKey).keyID(UUID.randomUUID().toString()).build();JWKSet jwkSet = new JWKSet(rsaKey);return new ImmutableJWKSet<>(jwkSet);}/*** 生成RSA256非对称的秘钥对:公钥和私钥,其中公钥会出布出去。* @return*/private static KeyPair generateRsaKey() {KeyPair keyPair;try {KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");keyPairGenerator.initialize(2048);keyPair = keyPairGenerator.generateKeyPair();}catch (Exception ex) {throw new IllegalStateException(ex);}return keyPair;}/*** jwt 解码器,给资源服务器用* @param jwkSource* @return*/@Beanpublic JwtDecoder jwtDecoder(JWKSource<SecurityContext> jwkSource) {return OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource);}/*** jwt 编码器,给授权服务器用* @param jwkSource* @return*/@Beanpublic JwtEncoder jwtEncoder(JWKSource<SecurityContext> jwkSource) {return new NimbusJwtEncoder(jwkSource);}/*** 默认授权服务器配置* @return*/@Beanpublic AuthorizationServerSettings authorizationServerSettings() {return AuthorizationServerSettings.builder().build();}
}

1.3SecurityConfig

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;@Configuration
@EnableWebSecurity
public class SecurityConfig {@Bean@Order(1)public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http)throws Exception {http.authorizeHttpRequests((authorize) -> authorize.anyRequest().authenticated()).oauth2ResourceServer(resourceServer -> resourceServer.jwt(Customizer.withDefaults()));return http.build();}}

1.4验证

需要注意,这里使用post + x-www-form-urlencoded来请求,这个是区别于老版本(大概应该是boot2.7以前)
在这里插入图片描述
如果你在springBoot2.7以前用过oauth2,对于上述的方式肯定会很蒙蔽,接下来我们来说明为啥会这样。

2老版本/oauth/token

如下为例,下面是我们一个老版本的oauth2的登录认证接口,这里我用密码模式来举例

http://127.0.0.1:8080/oauth/token?client_id=client_hutao&client_secret=secret_hutao&username=hutao&password=123456&grant_type=password
我们使用postMan调用,如下所示
在这里插入图片描述
两者一对比就能发现,老版在url里面传参数,新版在请求体x-www-form-urlencoded传参数。
老版oauth2使用我们比较熟悉的Spring框架的接口开发方式来实现,如下代码所示

@RequestMapping(value = "/oauth/token", method=RequestMethod.GET)@RequestMapping(value = "/oauth/token", method=RequestMethod.POST)@RequestParam Map<String, String> parameters

因此我们想要去阅读源码或者调试信息时,只需要对org.springframework.security.oauth2.provider.endpoint.TokenEndpoint打debug打断点就可以了,该代码阅读起来难度也比较小,很贴近我们比较常见的restful接口的开发。
在这里插入图片描述

3问题:认证接口变了

我们先抛开我们怎么搭建授权服务器的问题,以及我现在为什么要从springBoot2升级到springBoot3,先解决一个问题,那就是,我们做授权服务器来实现单点登录这些功能,为啥要这样做?因为我们有很多系统都会调用这个单点登录来实现登录。也就是说,我们的这个登录认证接口是被很系统正在使用的,现在如果直接就升级,会导致我们很多子系统要跟着改,这影响很大,因此,我们从springBoot2升级到springBoot3(没有商量,必须升级)以后,oauth2也得跟着升级,我们得保证oauth2跟着升级以后,我们在新版本的oauth2下,得适配以前其他系统对接的接口。

4新版本/oauth2/token

通过上面的案例,我们发现接口地址变了,以前是/oauth/token,现在是/oauth2/token,并且
现在TokenEndpoint它不见了,不是说换个名字,是正儿八经的被删除了,通过追踪发现,/oauth2/token的工作原理机制和/oauth/token完全不一样。

特性旧版 (Spring Security OAuth2)新版 (Spring Authorization Server)
依赖spring-security-oauth2(已废弃)spring-boot-starter-oauth2-authorization-server
端点类TokenEndpoint(显式 @FrameworkEndpoint)无集中式端点类,改为分散的 Filter + AuthenticationProvider OAuth2TokenEndpointFilter
请求方法支持 GET/POST /oauth/token仅支持 POST /oauth2/token
代码入口直接由 TokenEndpoint 处理通过过滤器链和认证提供者协作处理

4.1定位/oauth2/token

如下所示,当我们请求这个接口时,实际上是下面这个OAuth2TokenEndpointFilter处理,而不是以前的那种,TokenEndpoint中的@RequestMapping(value = “/oauth/token”)处理
在这里插入图片描述
如下所示,你就可以尽情的debug,查看请求参数或者报错信息,来帮助你定位问题了
在这里插入图片描述

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

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

相关文章

笔记本电脑实现网线内网 + Wi-Fi外网同时使用的配置方案

1、同时连接两个网络‌ 插入网线连接内网&#xff0c;确保内网IP地址正常获取&#xff08;如10.143.88.x&#xff09;&#xff1b;连接Wi-Fi接入外网&#xff0c;确认可正常访问互联网&#xff08;如网关为192.168.8.1&#xff09;。 2、 记录关键网络参数‌ 内网网关&#…

从韦斯利・卡普洛看北斗星咨询公司的技术咨询引领之路

在科技与商业深度交融的时代&#xff0c;技术咨询公司扮演着举足轻重的角色&#xff0c;它们宛如连接技术创新与企业实际需求的桥梁&#xff0c;助力企业在复杂多变的市场环境中找准技术发展方向&#xff0c;实现可持续增长。《对话 CTO&#xff0c;驾驭高科技浪潮》的第 5 章聚…

首版次软件测试的内容有哪些?首版次软件质量影响因素是什么?

首版次软件测试不仅是简单的“找错”&#xff0c;更是系统地验证和评估软件各项功能和性能指标是否符合设计标准。 一、首版次软件测试常见的测试内容   1.功能测试&#xff1a;对照需求文档&#xff0c;确认功能模块是否按预期实现&#xff0c;用户操作流程是否顺畅。   …

从零开始的python学习(六)P86+P87+P88

本文章记录观看B站python教程学习笔记和实践感悟&#xff0c;视频链接&#xff1a;【花了2万多买的Python教程全套&#xff0c;现在分享给大家&#xff0c;入门到精通(Python全栈开发教程)】 https://www.bilibili.com/video/BV1wD4y1o7AS/?p6&share_sourcecopy_web&v…

从设计到开发,原型标注图全流程标准化

一、原型标注图是什么&#xff1f; 原型标注图&#xff08;Annotated Prototype&#xff09;是设计原型&#xff08;Prototype&#xff09;的详细说明书&#xff0c;通过图文结合的方式&#xff0c;将设计稿中的视觉样式、交互逻辑、适配规则等技术细节转化为开发可理解的标准…

飞云分仓操盘副图指标操作技术图文分解

如上图&#xff0c;副图指标-飞云分仓操盘指标&#xff0c;指标三条线蓝色“首峰线”&#xff0c;红色“引力1”&#xff0c;青色“引力2”&#xff0c;多头行情时“首峰线”和“引力1”之间显示为红色&#xff0c;“引力1”和“引力2”多头是区间颜色显示为紫色。 如上图图标信…

【LUT技术专题】ECLUT代码解读

目录 原文概要 1. 训练 2. 转表 3. 测试 本文是对ECLUT技术的代码解读&#xff0c;原文解读请看ECLUT。 原文概要 ECLUT通过EC模块增大网络感受野&#xff0c;提升超分效果&#xff0c;实现SRLUT的改进&#xff0c;主要是2个创新点&#xff1a; 提出了一个扩展卷积&…

动态规划之背包问题:组合优化中的经典NP挑战

背包问题概念&#xff1a; 背包问题是一种经典的组合优化的NP问题&#xff0c;在计算机科学、运筹学等领域有着广泛的应用。 问题可以简单的描述为&#xff1a; 假设有一个容量为C的背包和n个物品&#xff0c;每个物品i都有重量w[i]和价值v[i]。目标是选择一些物品放入背包&…

vue3: pdf.js5.2.133 using typescript

npm install pdfjs-dist5.2.133 项目结构&#xff1a; <!--* creater: geovindu* since: 2025-05-09 21:56:20* LastAuthor: geovindu* lastTime: 2025-05-09 22:12:17* 文件相对于项目的路径: \jsstudy\vuepdfpreview\comonents\pdfjs.vue* message: geovindu* IDE: vscod…

H2Database SQL 插入流程

H2Database SQL 插入流程 插入数据时会先进行 SQL 解析,然后找到插入表对应的 Primary Index 对应的 BTree,然后根据二分法定位到插入的叶子节点,将 key(主键) 和 value(Row) 插入到指定的叶子节点. 解析 SQL session 加锁 创建 savepoint获取or创建事务 设置 savepoint 执行…

虚拟机ubantu20.04系统桥接模式下无法ping通外网,但可以ping通本机的解决方案

1.出现的问题&#xff1a; 虚拟机ubantu20.04系统桥接模式下无法ping通外网,但可以ping通本机。 2.解决方案&#xff1a; 如果 DHCP 未分配 IP 地址&#xff0c;可以手动配置静态 IP&#xff1a; 1.编辑网络配置文件&#xff1a; sudo nano /etc/netplan/01-netcfg.yaml 修…

面对渠道竞争,品牌该如何应对?

无论是传统零售渠道还是电商平台的&#xff0c;渠道竞争仍旧是品牌维持和扩大影响力绕不开的一环。品牌想要保证自身的市场地位和盈利能力&#xff0c;就需要充分发挥各方面的优势&#xff0c;来应对多变的市场环境。 一、改变产品定位 在存量市场上&#xff0c;消费者本身拥有…

SpringAI特性

一、SpringAI 顾问&#xff08;Advisors&#xff09; Spring AI 使用 Advisors机制来增强 AI 的能力&#xff0c;可以理解为一系列可插拔的拦截器&#xff0c;在调用 AI 前和调用 AI 后可以执行一些额外的操作&#xff0c;比如&#xff1a; 前置增强&#xff1a;调用 AI 前改…

101alpha_第6个

第6个alpha (-1 * correlation(open, volume, 10)) 这个就是看这两个相似性。10天之内的 如果结果为正且数值较大&#xff0c;投资者可能会认为在开盘价上涨时成交量萎缩&#xff0c;市场上涨动力不足&#xff0c;可能是卖出信号&#xff1b;反之&#xff0c;开盘价下跌时成交…

【渗透测试】Web服务程序解析漏洞原理、利用方式、防范措施

文章目录 Web服务程序解析漏洞原理、利用方式、防范措施一、原理**1. 定义与触发条件****2. 攻击链流程图** 二、利用方式**1. 常见漏洞类型与利用手法**(1) IIS 5.x-6.x解析漏洞(2) Apache解析漏洞(3) Nginx解析漏洞(4) IIS 7.x解析漏洞(5) PHP CGI解析漏洞&#xff08;CVE-20…

SSL证书格式详解:PEM、CER、DER、JKS、PKCS12等

引言 在网络安全领域&#xff0c;SSL/TLS证书是保障互联网通信安全的核心工具。它们通过加密连接&#xff0c;确保服务器与客户端之间的数据隐私和完整性。然而&#xff0c;对于初学者来说&#xff0c;SSL证书的多种格式——PEM、CER、JKS、PKCS12、PFX等——常常令人困惑。每…

生信服务器如何安装cellranger|生信服务器安装软件|单细胞测序软件安装

一.Why cellranger Cell Ranger 是由 10x Genomics 公司开发的一款用于处理其单细胞测序&#xff08;single-cell RNA-seq, scRNA-seq&#xff09;数据的软件套件。它主要用于将原始测序数据&#xff08;fastq 文件&#xff09;转换为可以用于下游分析的格式&#xff0c;比如基…

Redis 常见数据类型

Redis 常见数据类型 一、基本全局命令详解与实操 1. KEYS 命令 功能&#xff1a;按模式匹配返回所有符合条件的键&#xff08;生产环境慎用&#xff0c;可能导致阻塞&#xff09;。 语法&#xff1a; KEYS pattern 模式规则&#xff1a; h?llo&#xff1a;匹配 hello, ha…

33号远征队 - 游玩鉴赏

风景很好画质很好 , 图片太大只能截图一小部分 地编和特效 值得参考

使用JMETER中的JSON提取器实现接口关联

一、JSON提取器介绍 JSON提取器是JMETER工具中用于从JSON响应中提取数据的重要组件&#xff0c;常常用于接口关联场景中&#xff08;参数传递&#xff09;。 二、添加JSON提取器 举例&#xff08;积分支付接口请求数据依赖于创建订单接口响应的payOrderId&#xff09; 1.在…