导言
在学习OAuth2之前一直以为OAuth2和Spring Security一样是一个安全框架,了解以后才知道OAuth2其实是一种安全协议。下面说说什么是Spring Security又是怎么实现OAuth2的
Spring Security
Spring Security是Spring生态系统中提供身份验证(Authentication)、授权(Authorization) 和 安全防护功能的安全框架。它是企业级应用中最常用的安全解决方案之一,能够保护 Web 应用、微服务、API 接口等资源免受恶意攻击。
一、Spring Security核心机制解析
1、认证与授权流程
首先他是通过一系列的过滤器链来实现用户身份验证、授权、安全防护功能。
- 过滤器链(Filter Chain):11个默认过滤器构成安全防线,按照执行顺序如下(以典型 Spring Security 6.x 为例):
过滤器类名 | 作用描述 |
---|---|
SecurityContextPersistenceFilter | 在请求开始和结束时,从存储(如 HTTP Session)中加载或保存 SecurityContext (存储用户认证信息)。 |
HeaderWriterFilter | 向响应中添加安全相关的 HTTP 头(如 X-Content-Type-Options , X-Frame-Options ),防御 XSS、点击劫持等攻击。 |
CsrfFilter | 校验 CSRF 令牌,防御跨站请求伪造攻击(默认对非安全 HTTP 方法如 POST、PUT 启用)。 |
LogoutFilter | 处理退出登录请求(默认匹配 /logout 路径),清除用户认证信息。 |
UsernamePasswordAuthenticationFilter | 处理表单登录请求(默认匹配 /login 路径),将用户名密码封装为 Authentication 对象进行认证。 |
DefaultLoginPageGeneratingFilter | 自动生成默认登录页面(若未自定义登录页)。 |
DefaultLogoutPageGeneratingFilter | 自动生成默认退出确认页面(若未自定义)。 |
BasicAuthenticationFilter | 处理 HTTP Basic 认证请求(请求头携带 Authorization: Basic )。 |
RequestCacheAwareFilter | 缓存用户未登录前的请求,登录成功后自动重定向到原请求路径。 |
SecurityContextHolderAwareRequestFilter | 将 HttpServletRequest 包装为支持安全方法(如 isUserInRole() )的 SecurityContextHolderAwareRequestWrapper 。 |
AnonymousAuthenticationFilter | 为未登录用户自动分配一个匿名身份(AnonymousAuthenticationToken ),统一权限判断逻辑。 |
SessionManagementFilter | 管理用户会话(如防止会话固定攻击、控制并发会话数)。 |
ExceptionTranslationFilter | 捕获过滤器链中的异常(如 AccessDeniedException , AuthenticationException ),将其转换为对应的 HTTP 响应(如重定向到登录页、返回 403)。 |
FilterSecurityInterceptor | 最终防线:根据配置的权限规则,决定是否允许访问当前请求(如 URL 路径权限)。 |
- 核心接口:
UserDetailsService // 用户数据加载
AuthenticationProvider // 认证逻辑实现
SecurityContextHolder // 安全上下文存储
2、代码案例
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
SecurityFilterChain defaultFilterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.disable()) // 根据场景选择是否关闭
.authorizeHttpRequests(auth -> auth
.requestMatchers("/public/**").permitAll()
.requestMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
)
.formLogin(form -> form
.loginPage("/login")
.defaultSuccessUrl("/home")
);
return http.build();
}
}
OAuth2
1、OAuth2规范了授权登陆中有四种授权方式。
模式 | 适用场景 | 安全等级 |
---|---|---|
授权码模式 | 第三方Web应用接入 | ★★★★★ |
简化模式 | 纯前端SPA应用 | ★★☆☆☆ |
密码模式 | 内部信任系统(如移动端APP) | ★★★☆☆ |
客户端模式 | 服务间通信 | ★★☆☆☆ |
在OAuth2中有四种角色:用户、客户应用、授权服务、资源服务。通常情况下用户指的是使用人,例如在登录码云时https://gitee.com/login#lang=zh-CN,我们就用户,而码云提供的前端登录页面就是客户应用了,而下方的第三方登录方式就是授权服务例如github,码云的后端服务器为资源服务。
- 授权码模式:
授权码模式最为复杂同时也是安全性最高的方式。这种方式适用于兼具前后端的Web项目,因为有些项目只有后端或只有前端,并不适用授权码模式。其流程为:
Resource Owner 资源所有者(用户)
User-Agent 客户应用(如浏览器)
Authorization Server 授权服务器
Client 资源服务器
有人肯定会问,为什么授权服务器不直接返回一个访问令牌而是先返回一个授权码再获取访问令牌。这是为了提高安全性,不让令牌在客户端中传输增加令牌泄露的风险。后端通过授权码获取token的话可以使用https等方式保护token的安全性。这也是为什么授权码模式只适用于有前后端的项目中。
-
简化模式
当项目中只有前端工程没有后端服务时,前端就只能使用直接获取访问令牌的模式进行授权登录。 -
密码模式
登录时直接传输密码进行校验登录,一般在系统内部之间高度信任的情况下使用,比如公司中集团OA系统和子公司OA系统访问时。 -
客户端模式
客户端以自己的名义,而不是以用户的名义,向"服务提供商"进行 授权。适用于没有前端的命令行应用,即在命令行下请求令牌。一般用来提供给我们完全信任的服务器端服务。
Spring Security结合OAuth2
上面说的OAuth2中有四种角色,其中想要实现授权服务的功能就引入依赖spring-boot-starter-oauth2-resource-server
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
一般在实际使用中我们的授权服务都是使用其他的第三方服务例如GitHub、QQ、百度等所以不多做介绍。开发中更多的是实现资源服务的功能。所以要引入spring-boot-starter-oauth2-client依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
yml配置
spring:
security:
oauth2:
client:
registration:
github:
client-id: your-app-client-id
client-secret: your-app-client-secret