
🌷 古之立大事者,不惟有超世之才,亦必有坚忍不拔之志
🎐 个人CSND主页------Micro麦可乐的博客
🐥《Docker实操教程》专栏以最新的Centos版本为基础进行Docker实操教程,入门到实战
🌺《RabbitMQ》专栏19年编写主要介绍使用JAVA开发RabbitMQ的系列教程,从基础知识到项目实战
🌸《设计模式》专栏以实际的生活场景为案例进行讲解,让大家对设计模式有一个更清晰的理解
🌛《开源项目》本专栏主要介绍目前热门的开源项目,带大家快速了解并轻松上手使用
✨《开发技巧》本专栏包含了各种系统的设计原理以及注意事项,并分享一些日常开发的功能小技巧
💕《Jenkins实战》专栏主要介绍Jenkins+Docker的实战教程,让你快速掌握项目CI/CD,是2024年最新的实战教程
🌞《Spring Boot》专栏主要介绍我们日常工作项目中经常应用到的功能以及技巧,代码样例完整
🌞《Spring Security》专栏中我们将逐步深入Spring Security的各个技术细节,带你从入门到精通,全面掌握这一安全技术
如果文章能够给大家带来一定的帮助!欢迎关注、评论互动~
最新Spring Security实战教程(十四)OAuth2.0精讲 - 四种授权模式与资源服务器搭建
- [1. 前言(OAuth2简介)](#1. 前言(OAuth2简介))
- [2. OAuth2的角色](#2. OAuth2的角色)
- [3. OAuth 2.0 四种授权模式](#3. OAuth 2.0 四种授权模式)
-
- [3.1 授权码模式(Authorization Code Grant)](#3.1 授权码模式(Authorization Code Grant))
- [3.2 隐式模式(Implicit Grant)](#3.2 隐式模式(Implicit Grant))
- [3.3 客户端凭证模式(Client Credentials Grant)](#3.3 客户端凭证模式(Client Credentials Grant))
- [3.4 资源所有者密码凭证模式(Resource Owner Password Credentials Grant)](#3.4 资源所有者密码凭证模式(Resource Owner Password Credentials Grant))
- [3.5 总结](#3.5 总结)
- [4. 授权服务器与资源服务器搭建](#4. 授权服务器与资源服务器搭建)
-
- [❶ 引入依赖](#❶ 引入依赖)
- [❷ 授权服务器配置](#❷ 授权服务器配置)
- [❸ 资源服务器配置](#❸ 资源服务器配置)
- [❹ 完整示例代码](#❹ 完整示例代码)
- 结语:构建开放安全的认证生态
回顾链接:
最新Spring Security实战教程(一)初识Spring Security安全框架
最新Spring Security实战教程(二)表单登录定制到处理逻辑的深度改造
最新Spring Security实战教程(三)Spring Security 的底层原理解析
最新Spring Security实战教程(四)基于内存的用户认证
最新Spring Security实战教程(五)基于数据库的动态用户认证传统RBAC角色模型实战开发
最新Spring Security实战教程(六)最新Spring Security实战教程(六)基于数据库的ABAC属性权限模型实战开发
最新Spring Security实战教程(七)方法级安全控制@PreAuthorize注解的灵活运用
最新Spring Security实战教程(八)Remember-Me实现原理 - 持久化令牌与安全存储方案
最新Spring Security实战教程(九)前后端分离认证实战 - JWT+SpringSecurity无缝整合
最新Spring Security实战教程(十)权限表达式进阶 - 在SpEL在安全控制中的高阶魔法
最新Spring Security实战教程(十一)CSRF攻防实战 - 从原理到防护的最佳实践
最新Spring Security实战教程(十二)CORS安全配置 - 跨域请求的安全边界设定
最新Spring Security实战教程(十三)会话管理机制 - 并发控制与会话固定攻击防护
专栏更新完毕后,博主将会上传所有章节代码到CSDN资源免费给大家下载,如你不想等后续章节代码需提前获取,可以私信或留言!
1. 前言(OAuth2简介)

目前 OAuth2.0
已成为现代应用认证授权的一个标准,从单点登录到微服务架构都依赖其构建安全通道。我们常见的微信、QQ、微博等应用有在使用。OAuth 2.0(Open Authorization)
是一种开放的授权框架,允许应用在不暴露用户密码的前提下,安全地代表用户访问第三方服务上的受保护资源。
本章节博主将带着大家深入解析四种核心授权模式,并基于 Spring Security 6
手把手搭建安全的资源服务器,助您掌握分布式系统的认证精髓。
注:博主部分介绍参考了官方文档:https://docs.spring.io/spring-security/reference/servlet/oauth2/index.html 小伙伴们可以自行阅读、并查阅官方DEMO代码
2. OAuth2的角色
根据 RFC 6749 标准,OAuth 2.0
定义了四种角色,每个角色在授权流程中承担不同职责
-
资源所有者(Resource Owner) :通常是终端用户,拥有受保护资源
-
客户端(Client):向用户请求授权,代表用户访问资源的应用,通常是一个Web或者无线应用
-
授权服务器(Authorization Server):认证资源所有者身份并颁发访问令牌
-
资源服务器(Resource Server):托管资源并根据令牌的有效性和权限范围决定是否允许访问
为了让小伙伴们更好的理解博主用一个现实生活中的场景(小区门禁系统)来类比OAuth2.0
的工作原理,帮你直观理解它的角色和四种授权模式。

场景:小区门禁系统
假设你住在一个需要刷卡或扫码进入的小区,门禁系统要求验证身份后才能开门。以下是 OAuth2.0 的四个角色映射:
-
资源所有者(Resource Owner)
住户(你):你是小区住户,拥有进出小区的权限。
-
客户端(Client)
快递员或访客:需要临时进入小区的人或设备(比如快递员的小程序)
-
授权服务器(Authorization Server)
物业中心:负责验证住户身份,并发放临时通行权限(令牌)
-
资源服务器(Resource Server)
小区门禁闸机:接收令牌(如二维码或门禁卡),验证后决定是否放行
OAuth2的核心逻辑
-
你(住户)不想直接给快递员门禁卡或密码,而是通过物业中心生成一个临时二维码(
令牌
),限制其权限(例如:仅允许进入1次,或仅在30分钟内有效)。 -
令牌由物业中心发放,你可以随时在物业系统中吊销它。
3. OAuth 2.0 四种授权模式
不同场景下,OAuth 2.0
定义了四种核心授权模式,各有适用范围和安全考量
3.1 授权码模式(Authorization Code Grant)
授权码(authorization code),指的是第三方应用先申请一个授权码,然后再用该码获取令牌。
这种方式是最常用,最复杂,也是最安全的,它适用于那些有后端的 Web 应用。授权码通过前端传送,令牌则是储存在后端,而且所有与资源服务器的通信都在后端完成。这样的前后端分离,可以避免令牌泄漏。
场景 :适用于安全的服务端 Web 应用,例如电商网站在结算时需要访问支付平台 API。
流程 :
1、客户端引导用户浏览器跳转到授权服务器授权端点;
2、用户登录并同意后,授权服务器重定向携带 code 到客户端回调 URL;
3、客户端使用该 code 向令牌端点申请访问令牌,并在请求中携带客户端凭证。
优点 :令牌通过后端交换,避免在浏览器中暴露,安全性较高
现实生活模拟场景
还是以上述小区门禁系统来举例:快递员通过「小区快递App」申请进入权限
1、快递员点击APP「申请进入小区」,App 跳转到物业的授权页面。
2、你(住户)在物业APP上接收到授权通知,并同意授权(例如:允许快递员在30分钟内进入小区1次)。
3、物业中心生成一个授权码返回给快递员的快递App。
4、快递App 用授权码向物业中心换取一个临时二维码(令牌)。
5、快递员用二维码扫码进入小区门禁(资源服务器)。
3.2 隐式模式(Implicit Grant)
场景:传统的单页应用(SPA
)或无法安全存储客户端密钥的纯前端应用。
流程:用户同意授权后,授权服务器直接在重定向 URI
的 fragment
中返回访问令牌,无需第二次交换。
缺点:令牌暴露在浏览器,易受截取攻击,注:Spring Security 6 已移除隐式模式支持,使用PKCE增强的授权码模式
java
// Spring Security 6已移除隐式模式支持
http.oauth2Client(oauth2 -> oauth2
.authorizationCodeGrant(Customizer.withDefaults())
)
现实生活模拟场景
访客临时申请进入小区:
1、访客在门禁屏幕上点击「申请临时通行」。
2、直接跳转到物业授权页面,你登录并同意授权。
3、物业中心直接返回一个临时二维码(令牌)到门禁屏幕的URL中。
4、访客用二维码扫码进入,但二维码仅在5分钟内有效。
3.3 客户端凭证模式(Client Credentials Grant)
凭证式(client credentials):也叫客户端模式,适用于没有前端的命令行应用,即在命令行下请求令牌。
这种方式给出的令牌,是针对第三方应用的,而不是针对用户的,即有可能多个用户共享同一个令牌
场景:应用间 M2M 通信,如后台微服务之间相互调用私有 API。
流程:客户端直接向令牌端点发送 grant_type=client_credentials
请求,并在 HTTP Basic Auth
中提供客户端 ID/密钥,即可获取访问令牌。
特点:不涉及用户,适合服务账户场景,配置简单且安全性可控
现实生活模拟场景
物业巡逻车需要进出小区所有区域
1、物业巡逻车用自己的工牌(客户端ID和密钥)向物业中心申请令牌。
2、物业中心验证工牌后,发放一个万能通行令牌(可进入所有区域)。
3、巡逻车凭令牌自由进出小区门禁。
3.4 资源所有者密码凭证模式(Resource Owner Password Credentials Grant)
密码式(Resource Owner Password Credentials):如果你高度信任某个应用,RFC 6749 也允许用户把用户名和密码,直接告诉该应用。该应用就使用你的密码,申请令牌
这种方式需要用户给出自己的用户名/密码,显然风险很大,因此只适用于其他授权方式都无法采用的情况,而且必须是用户高度信任的应用
场景:高度信任的客户端(如官方移动端应用)与授权服务器共属一个安全域时,可直接收集用户名和密码。
流程:客户端将用户名、密码与自身凭证一起 POST
到令牌端点,授权服务器验证后颁发令牌。
风险:客户端需处理用户敏感凭证,安全性最低,通常仅在无法采用授权码模式时作为后备方案
现实生活模拟场景
你的家人定期出入小区(物业通过你的账号密码给其他人授权)
1、你直接将门禁账号密码授权给到家人。
2、家人用你的账号密码向物业中心申请长期有效的通行令牌。
3、物业返回令牌,家人人凭令牌进出小区。
3.5 总结
模式 | 门禁场景类比 | 权限范围 | 风险 |
---|---|---|---|
授权码模式 | 快递员通过App申请临时通行 | 限时、限次 | 低(令牌不暴露) |
隐式模式 | 访客直接扫码获得短期通行 | 超短时效 | 中(URL暴露令牌) |
密码模式 | 自家家人长期通行 | 长期有效 | 高(需信任设备) |
客户端凭证模式 | 物业巡逻车自由通行 | 全权限 | 中(客户端可控) |
4. 授权服务器与资源服务器搭建
讲解了 OAuth2
四种授权模式,下面我们来实现授权服务器与资源服务器搭建
❶ 引入依赖
在 Spring Boot 3
+ Spring Security 6
项目中,添加以下依赖即可快速构建授权服务器与资源服务器:
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-authorization-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
❷ 授权服务器配置
使用 OAuth2AuthorizationServerConfigurer
和基于内存的 RegisteredClientRepository
快速配置:
java
@Configuration
public class AuthServerConfig {
@Bean
public RegisteredClientRepository registeredClientRepository() {
RegisteredClient client = RegisteredClient.withId(UUID.randomUUID().toString())
.clientId("web-client")
.clientSecret("{noop}web-secret")
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
.redirectUri("http://localhost:8080/login/oauth2/code/web-client")
.scope("read")
.build();
return new InMemoryRegisteredClientRepository(client);
}
@Bean
public SecurityFilterChain authServerSecurityFilterChain(HttpSecurity http) throws Exception {
OAuth2AuthorizationServerConfigurer<HttpSecurity> configurer = new OAuth2AuthorizationServerConfigurer<>();
http.apply(configurer).and()
.exceptionHandling(ex -> ex.authenticationEntryPoint(
new LoginUrlAuthenticationEntryPoint("/login")
));
return http.build();
}
}
该配置启用了授权码与客户端凭证模式,并自动暴露 /oauth2/authorize
、/oauth2/token
等端点
❸ 资源服务器配置
在 application.yml
中指定授权服务器的 issuer-uri
:
yaml
spring:
security:
oauth2:
resourceserver:
jwt:
issuer-uri: http://localhost:9000
并通过 Lambda DSL
定义安全规则:
java
@Configuration
public class ResourceServerConfig {
@Bean
public SecurityFilterChain resourceServerSecurityFilterChain(HttpSecurity http) throws Exception {
http
.securityMatcher("/api/**")
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/public").permitAll()
.anyRequest().authenticated()
)
.oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()));
return http.build();
}
}
此时,所有 /api/**
请求均需携带合法的 JWT
访问令牌,否则会返回 401/403
错误
❹ 完整示例代码
结合上述讲解,我们将完整代码展示如下:
java
@SpringBootApplication
public class OAuth2ServerApplication {
public static void main(String[] args) {
SpringApplication.run(OAuth2ServerApplication.class, args);
}
// 注册客户端
@Bean
public RegisteredClientRepository registeredClientRepository() {
RegisteredClient appClient = RegisteredClient.withId(UUID.randomUUID().toString())
.clientId("app-client")
.clientSecret("{noop}app-secret")
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
.redirectUri("http://localhost:8080/login/oauth2/code/app-client")
.scope("read")
.build();
return new InMemoryRegisteredClientRepository(appClient);
}
// 授权服务器安全链
@Bean
@Order(1)
public SecurityFilterChain authServerFilterChain(HttpSecurity http) throws Exception {
OAuth2AuthorizationServerConfigurer<HttpSecurity> oauth2Config = new OAuth2AuthorizationServerConfigurer<>();
http.apply(oauth2Config).and()
.csrf(csrf -> csrf.ignoringRequestMatchers("/oauth2/token"))
.exceptionHandling(ex -> ex.authenticationEntryPoint(
new LoginUrlAuthenticationEntryPoint("/login")
));
return http.build();
}
// 资源服务器安全链
@Bean
@Order(2)
public SecurityFilterChain resourceServerFilterChain(HttpSecurity http) throws Exception {
http
.securityMatcher("/api/**")
.authorizeHttpRequests(auth -> auth.anyRequest().authenticated())
.oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()));
return http.build();
}
}
在此示例中,同一应用既扮演授权服务器,也作为资源服务器提供 /api/**
保护接口,启动后即可体验完整的 OAuth 2.0
流程。
结语:构建开放安全的认证生态
OAuth2.0
的威力在于其灵活的协议设计,但灵活也意味着责任:
- 模式选型:根据场景选择最合适的授权流程
- 密钥管理:采用HSM或KMS保护签名密钥
- 监控审计:记录所有令牌发放与使用日志
- 协议演进:跟进OAuth2.1安全增强规范
通过本章节讲解与实战示例,相信小伙伴们已掌握 OAuth 2.0 的核心概念、四大角色、四种授权模式及其在 Spring Security 6 中的配置方式。后续可根据业务需求,引入 PKCE、刷新令牌、动态客户端注册等高级特性,进一步提升系统安全性与可扩展性。
如果你在实践过程中有任何疑问或更好的扩展思路,欢迎在评论区留言,最后希望大家 一键三连 给博主一点点鼓励!
