在前后端分离的架构下,后端API接口是业务的核心入口,也常常是安全防护的薄弱环节。一个接口漏洞可能导致数据泄露甚至系统瘫痪。而作为Spring生态的官方安全框架,Spring Security无疑是实现API接口全方位安全防护的最佳选择。
本文以实战落地为核心,将带你基于Spring Boot 3.x与Spring Security 6.x,一站式构建企业级API接口安全体系。内容涵盖从核心的认证授权、JWT无状态登录,到细粒度的RBAC权限控制,乃至接口防刷、XSS/CSRF防护等高级能力,所有配置规范通用,可直接复用于你的项目。
一、为什么API接口必须做安全防护?
前后端分离架构中,前端所有请求都通过调用后端API接口完成,这些直接暴露在网络中的接口面临着无处不在的安全风险:
- 匿名非法访问:未登录用户直接调用需权限的接口,窃取敏感数据;
- 越权操作:低权限用户调用高权限接口,执行删除、修改等危险操作;
- 账号密码泄露:明文传输或弱密码导致账号被盗,引发数据泄露;
- 接口恶意调用:短时间内高频调用接口,耗尽服务器资源导致系统崩溃;
- 跨站请求伪造与脚本注入:通过构造非法请求或注入恶意脚本,窃取信息或篡改数据;
- 令牌泄露风险:登录凭证被盗,攻击者冒充合法用户访问所有接口。
基于Spring Security的防护,核心目标就是建立一套完整的安全校验体系,将所有非法请求拦截在外,最终实现:合法用户、合法权限、合法请求,才能访问合法接口。
本次实战技术栈:Spring Boot 3.x + Spring Security 6.x + JWT + RBAC权限模型,这是目前企业级项目中最主流、最成熟的接口安全解决方案。
二、Spring Security接口防护核心原理
在开始配置前,理解Spring Security的核心工作逻辑至关重要,所有的安全配置都基于此原理展开。
1. 核心机制:过滤器链(Filter Chain)
Spring Security的执行逻辑基于过滤器链。API请求到达后端后,不会直接进入Controller,而是会依次经过过滤器链中的多个安全过滤器。每个过滤器负责一个维度的安全校验,只有通过所有校验,请求才能执行业务逻辑。
针对API接口防护,常用的核心过滤器包括:
- Jwt认证过滤器:自定义过滤器,解析并校验请求头中的JWT令牌。
- UsernamePasswordAuthenticationFilter:处理用户登录的账号密码校验。
- SecurityContextPersistenceFilter:管理安全上下文,存储认证成功的用户信息。
- FilterSecurityInterceptor:权限校验的最终关卡,校验用户是否有接口访问权限。
- ExceptionTranslationFilter:统一处理过滤器链中的安全异常,返回标准化错误响应。
2. 两大核心能力:认证 & 授权
所有API接口安全防护,都围绕认证和授权两大核心展开。
✅ 认证:验证「你是谁」
这是第一道防线,解决“用户是否合法”的问题。核心逻辑是校验请求发起者是否为系统合法用户,例如登录时校验账号密码,调用接口时校验JWT令牌。
- 结果:认证通过则放行进入授权校验;认证失败则拦截并返回
401 未认证 响应。
- 规则:所有需要登录后才能访问的接口,必须完成认证。
✅ 授权:验证「你能做什么」
这是第二道防线,建立在认证通过的基础上,解决“用户是否有权限”的问题。核心逻辑是校验已认证的用户是否有资格访问当前接口。
- 结果:授权通过则放行执行业务逻辑;授权失败则拦截并返回
403 无权限访问 响应。
- 规则:不同角色、权限的用户,能访问的接口范围必须严格区分。
3. 无状态认证:JWT核心适配逻辑
传统的Session认证在服务器端存储会话信息,分布式场景下繁琐。本次实战采用 JWT + Spring Security 实现无状态认证。
- 核心优势:服务器端不存储任何用户会话信息,用户身份、角色等信息全部加密存储在JWT令牌中,由客户端存储和携带。
- 核心逻辑:用户登录后,后端生成JWT令牌返回;前端后续请求在请求头中携带该令牌;后端通过自定义过滤器解析令牌完成认证授权。这种方式完美适配分布式与微服务场景。
三、实战一:基础环境搭建与核心依赖
首先完成基础环境搭建,所有配置追求最简、最优、可直接复用。
1. 核心依赖(pom.xml)
仅需引入以下4类核心依赖,Spring Boot对Spring Security有完美的自动配置支持。
<!-- Spring Web 核心依赖,实现API接口 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Security 核心安全依赖,接口防护核心 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- JWT 令牌生成、解析、校验依赖 -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.5</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
<!-- Lombok 简化实体类代码,可选 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
2. 核心前置规范
约定以下核心规范,以降低开发和维护成本:
- 接口访问规范:需登录认证的接口,必须在请求头中携带JWT令牌,格式为:
Authorization: Bearer 令牌字符串。
- 权限标识规范:采用RBAC权限模型。角色标识以
ROLE_开头(如ROLE_ADMIN),权限标识采用模块:操作格式(如user:list)。
- 接口分类规范:明确区分公开接口(无需登录)、认证接口(只需登录)、权限接口(登录+指定权限),分开配置。
四、实战二:核心配置落地 - 一站式实现全维度安全防护
这是本次实战的核心,采用“核心配置类+自定义组件”的方式,实现完整的API接口安全能力。
1. 第一步:核心配置类 - SpringSecurityConfig
这是所有安全规则、过滤器的配置入口。
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import javax.annotation.Resource;
/**
* Spring Security 核心配置类 - API接口安全防护核心配置
*/
@Configuration
@EnableWebSecurity // 开启Spring Security核心功能
@EnableMethodSecurity // 开启方法级别的权限注解(核心,接口权限控制必备)
public class SpringSecurityConfig {
// 注入自定义JWT认证过滤器
@Resource
private JwtAuthenticationFilter jwtAuthenticationFilter;
// 注入自定义安全异常处理器
@Resource
private CustomAccessDeniedHandler accessDeniedHandler;
@Resource
private CustomAuthenticationEntryPoint authenticationEntryPoint;
/**
* 配置核心过滤器链 & 接口安全规则
*/
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
return http
// 1. 关闭CSRF防护:前后端分离的API接口,无需CSRF防护,关闭提升性能
.csrf(csrf -> csrf.disable())
// 2. 关闭表单登录:API接口都是JSON请求,无需默认表单登录页面
.formLogin(form -> form.disable())
// 3. 关闭HTTP基础认证:无需浏览器弹窗账号密码校验
.httpBasic(basic -> basic.disable())
// 4. 配置Session策略:核心!STATELESS无状态,禁用Session,实现JWT无状态认证
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
// 5. 配置接口访问规则:核心,区分公开接口和受保护接口
.authorizeHttpRequests(auth -> auth
// 公开接口:放行,无需认证、无需权限(如登录、注册、验证码接口)
.requestMatchers("/api/auth/login", "/api/auth/register", "/api/public/**").permitAll()
// 所有其他接口:必须完成认证才能访问,未认证则拦截
.anyRequest().authenticated()
)
// 6. 添加自定义JWT过滤器:在用户名密码过滤器之前执行,优先校验令牌
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
// 7. 配置全局异常处理器:统一处理未认证、无权限等安全异常
.exceptionHandling(ex -> ex
.authenticationEntryPoint(authenticationEntryPoint) // 未认证异常
.accessDeniedHandler(accessDeniedHandler) // 无权限异常
)
.build();
}
/**
* 密码加密器:核心!必须使用BCrypt加密,禁止明文存储密码
*/
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
/**
* 认证管理器:处理账号密码的认证逻辑,登录时必备
*/
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception {
return config.getAuthenticationManager();
}
}
2. 第二步:核心自定义组件
通过自定义组件实现适配API接口的核心能力,所有组件均为通用实现。
✅ 组件1:Jwt工具类 - JwtUtils
封装JWT令牌的生成、解析、校验核心方法。
import io.jsonwebtoken.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
/**
* JWT令牌工具类 - 生成、解析、校验令牌
*/
@Component
@Slf4j
public class JwtUtils {
// JWT签名密钥,生产环境建议配置在文件中,妥善保管
@Value("${jwt.secret:spring-security-jwt-api-secret-key}")
private String secretKey;
// JWT令牌过期时间,默认2小时,可按需调整
@Value("${jwt.expiration:7200000}")
private long expirationTime;
// 生成JWT令牌:传入用户信息,生成包含用户名、角色的令牌
public String generateToken(UserDetails userDetails) {
Map<String, Object> claims = new HashMap<>();
return createToken(claims, userDetails.getUsername());
}
// 核心生成令牌方法
private String createToken(Map<String, Object> claims, String subject) {
return Jwts.builder()
.setClaims(claims)
.setSubject(subject)
.setIssuedAt(new Date(System.currentTimeMillis()))
.setExpiration(new Date(System.currentTimeMillis() + expirationTime))
.signWith(SignatureAlgorithm.HS256, secretKey)
.compact();
}
// 校验令牌是否合法:用户名匹配 + 未过期
public boolean validateToken(String token, UserDetails userDetails) {
final String username = extractUsername(token);
return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
}
// 解析令牌中的用户名
public String extractUsername(String token) {
return extractClaim(token, Claims::getSubject);
}
// 解析令牌中的过期时间
public Date extractExpiration(String token) {
return extractClaim(token, Claims::getExpiration);
}
// 通用解析方法
public <T> T extractClaim(String token, Function<Claims, T> claimsResolver) {
final Claims claims = extractAllClaims(token);
return claimsResolver.apply(claims);
}
// 解析令牌所有信息
private Claims extractAllClaims(String token) {
return Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token).getBody();
}
// 判断令牌是否过期
private boolean isTokenExpired(String token) {
return extractExpiration(token).before(new Date());
}
}
✅ 组件2:自定义JWT认证过滤器 - JwtAuthenticationFilter
这是核心中的核心,所有API请求都会经过它。其作用是拦截并校验JWT令牌,解析用户信息并存入安全上下文,完成自动认证。
✅ 组件3:统一安全异常处理器
包含“未认证异常处理器”和“无权限异常处理器”,确保返回标准化的JSON错误响应,而非默认错误页面。
- 未认证(401):
{"code":401,"msg":"请先登录后再操作","data":null}
- 无权限(403):
{"code":403,"msg":"无权限访问该接口","data":null}
✅ 组件4:用户信息服务 - UserDetailsService
根据用户名查询数据库中的用户信息、角色、权限,并封装为Spring Security的用户对象。这是连接数据库与Spring Security、实现RBAC权限模型的核心桥梁。
3. 第三步:接口级别的细粒度权限控制
通过注解实现接口级别的细粒度权限控制,这是最常用、最灵活的方式。所有注解需加在Controller接口方法上,生效前提是在核心配置类上添加了 @EnableMethodSecurity。
✅ 注解1:@PreAuthorize 【推荐,最常用】
方法执行前进行权限校验,支持SpringEL表达式,可校验角色、权限或组合条件。
- 校验角色:
@PreAuthorize("hasRole('ROLE_ADMIN')")
- 校验权限:
@PreAuthorize("hasAuthority('user:delete')")
- 组合条件:
@PreAuthorize("hasRole('ROLE_ADMIN') or hasAuthority('order:list')")
✅ 注解2:@Secured
语法简单,仅支持角色校验。
- 示例:
@Secured({"ROLE_ADMIN", "ROLE_USER"})
✅ 注解3:@PostAuthorize
方法执行后进行权限校验,适用于需根据返回结果判断权限的场景,API接口中使用较少。
五、实战三:高级安全能力补充(生产必备)
基于核心配置,我们已实现基础防护。但在生产环境中,还需针对常见攻击方式集成以下高级安全能力。
✅ 能力一:密码安全加固
- 强制密码加密存储:通过
BCryptPasswordEncoder对密码进行不可逆加密存储。
- 密码强度校验:自定义规则,要求密码包含大小写字母、数字、特殊字符,长度不少于8位。
✅ 能力二:接口防刷限流
针对恶意高频调用,基于过滤器链集成接口限流能力。
- 对所有API接口设置访问频率限制(如每分钟60次)。
- 对高频调用IP进行临时封禁。
- 限流拦截后返回
429 请求过于频繁 的标准化响应。
✅ 能力三:XSS攻击防护
通过自定义过滤器对所有请求参数进行XSS清洗。
- 过滤请求头、请求体中的
<script>、<iframe> 等恶意标签。
- 对
<、>、& 等特殊字符进行转义。
- 全程无侵入,不影响业务逻辑。
✅ 能力四:敏感接口风控
对删除、修改权限、资金操作等高危接口,增加双重保障。
- 操作日志记录:记录调用者、时间、操作内容、IP地址,便于审计追溯。
- 二次身份校验:要求用户再次输入密码或验证码,即使令牌被盗也无法执行高危操作。
六、核心最佳实践(避坑指南)
规范的使用和最佳实践,是保障接口安全的核心。以下8条生产环境必遵守的实践,能帮你规避绝大多数安全问题。
✅ 最佳实践1:严格区分接口类型
公开接口(登录、注册等)必须单独配置放行,切勿将受保护接口误配为公开接口。除公开接口外,所有接口必须要求认证。
✅ 最佳实践2:遵循「最小权限原则」
分配权限时,只给用户其业务所需的最小权限。接口权限按“模块+操作”细分,避免配置统一的粗粒度角色权限。
✅ 最佳实践3:JWT令牌安全管理(重中之重)
- 令牌过期时间建议1-2小时,不宜过长。
- 生产环境签名密钥建议使用RSA非对称加密替代HS256对称加密。
- 令牌建议存储在前端
localStorage或会话存储中,禁止存储在Cookie中以防XSS窃取。
- 实现令牌刷新机制,在令牌临期时自动刷新。
- 用户登出时,前端立即删除令牌,后端可将旧令牌加入Redis黑名单实现主动吊销。
✅ 最佳实践4:统一异常响应,禁止返回敏感信息
所有安全异常必须返回标准化JSON响应,禁止返回堆栈信息、数据库表名、接口路径等敏感信息。错误提示应简洁,不泄露内部逻辑。
✅ 最佳实践5:禁止在JWT令牌中存储敏感数据
JWT载荷部分是Base64编码,属于明文,因此只能存储用户ID、用户名、角色等非敏感信息。密码、手机号等绝对禁止存入。
✅ 最佳实践6:定期更新令牌密钥,做好安全巡检
生产环境建议每3个月更新一次JWT签名密钥。定期巡检接口访问日志,排查异常访问频率和IP。
✅ 最佳实践7:禁用无用的安全策略
前后端分离的API接口,必须关闭CSRF防护、表单登录、HTTP基础认证,并使用无状态认证,以提升性能。
✅ 最佳实践8:做好接口文档的权限控制
接口文档(如Swagger)必须配置访问权限,生产环境禁止暴露。测试环境的文档应只允许内网访问。
七、核心总结
本次实战基于Spring Security,从认证授权到JWT无状态登录,再到生产级高级防护,完整实现了API接口的全维度安全。所有配置均简洁、高效、可复用。
Spring Security之所以成为API接口安全防护的首选,其核心价值在于:
- 一站式解决方案:一个框架搞定所有安全需求,降低开发和维护成本。
- 高度可定制化:通过自定义组件可完美适配任何业务场景。
- 无缝集成Spring生态:与Spring Boot、Spring Cloud完美兼容,学习成本低。
- 企业级成熟度:经过多年生产环境验证,安全性和稳定性毋庸置疑。
API接口的安全防护是一个持续优化的过程。基于Spring Security搭建的这套安全体系,能有效抵御绝大多数常见攻击。希望本文的配置与最佳实践,能助你构建一个安全、可靠、健壮的API接口体系。如需探讨更多后端架构与安全实践,欢迎访问云栈社区进行交流。