前言

接口安全不是只在登录接口签发一个 Token,而是覆盖身份确认、访问控制、数据范围、凭证保护和攻击防护的完整链路。本文以 Spring Security 的过滤链为主线,说明 Session、JWT、OAuth2 及接口安全治理在企业系统中的职责边界。

认证、授权与数据权限不是一回事

认证回答“你是谁”,授权回答“你能访问哪个接口或动作”,数据权限回答“你能访问哪些具体订单、租户或部门数据”。Spring Security 主要提供认证和授权框架能力,数据权限仍要在查询条件与业务服务中落实。

flowchart LR
    A[HTTP Request] --> B[SecurityFilterChain]
    B --> C[Authentication Filter]
    C --> D[AuthenticationManager]
    D --> E[AuthenticationProvider]
    E --> F[SecurityContext]
    F --> G[AuthorizationFilter]
    G --> H[Controller / Service]

SecurityFilterChain 与认证流程

Spring Security 基于一条或多条 SecurityFilterChain 工作。请求先按 matcher 选择匹配链,再经过认证、异常转换、授权等过滤器。现代 Spring Security 推荐显式声明 SecurityFilterChain Bean,而非旧式继承配置适配器。

认证成功后得到 Authentication,其中包括 principal、权限集合和认证状态,并保存到 SecurityContext。Session 模式通常由 SecurityContextRepository 持久化上下文;Bearer Token 模式一般每次请求解析并验证 Token,不依赖服务端 Session。

模式 适合场景 关键风险
Session + Cookie 同域 Web 后台、服务端渲染 CSRF、Session 固定攻击、分布式 Session 和注销传播
JWT Bearer Token 移动端、前后端分离、网关传递身份 Token 泄露、撤销困难、过期策略、签名算法与 Key 轮换
OAuth2/OIDC 第三方登录、企业 SSO、资源服务器 正确校验 issuer、audience、scope、授权码回调与 PKCE

JWT 不是“天然更安全”。它是签名的令牌,通常不加密;不要把密码、身份证、完整权限明细等敏感信息放入 payload。验证必须限制允许算法,校验签名、过期时间、issuer、audience,并处理 Key 轮换。高风险注销可用短 access token + refresh token、服务端会话版本/黑名单或 token jti 机制,但要评估存储和一致性成本。

密码、登录和防暴力破解

密码只能保存为带盐的自适应哈希,例如 BCrypt、Argon2 或 PBKDF2,绝不能保存明文、可逆加密或普通 MD5/SHA。使用 PasswordEncoder.matches(raw, encoded) 验证,不能自行比较 hash 字符串。

登录接口还应限制 IP、账号、设备维度的失败次数,使用渐进延迟、验证码或临时锁定,并记录安全审计。错误提示不要区分“用户不存在”和“密码错误”,避免账号枚举。刷新 Token、找回密码、修改手机号等敏感流程需再次验证身份并防重放。

授权:URL、方法与数据

URL 授权适合粗粒度边界,例如公开健康检查、管理员路径、普通登录态接口;方法级 @PreAuthorize 更接近业务动作,例如退款审批。两者应保持一致的权限命名与来源,不能只在 Controller 保护而让 MQ 消费、定时任务或内部调用绕过核心业务授权。

1
2
3
4
@PreAuthorize("hasAuthority('order:refund:approve')")
public void approveRefund(Long refundId) {
// 还要校验当前操作人所属租户、订单范围和审批职责
}

表达式校验不能代替数据权限。查询订单列表时必须在 SQL/Repository 层附加 tenant_id、组织范围或数据归属条件;只校验请求中的 tenantId 等于当前用户输入值没有意义,因为参数来自不可信客户端。

CSRF、CORS 与常见接口风险

CSRF 针对浏览器自动携带 Cookie 的认证模式。Session Cookie 身份的修改类请求应保留 CSRF 防护或采用同站策略和可靠 token 方案;纯 Bearer Token 且不由浏览器自动携带时,CSRF 风险模型不同,但仍要防 XSS 窃取 Token。

CORS 是浏览器同源策略的响应头协商,不是服务端授权。不要配置 Access-Control-Allow-Origin: * 同时允许凭证;应明确可信源、方法、Header 和预检缓存。除此以外还要治理:输入校验、SQL 注入、XSS、SSRF、文件上传、重放、越权、敏感日志和错误信息泄露。

生产配置与排查

现象 常见原因 排查和修复
永远 401 Token 未传/格式错误、签名 Key 不一致、时钟偏差 查看认证失败原因,统一网关和服务时钟,校验 issuer/audience
已登录但 403 权限未映射为 GrantedAuthority、URL/方法规则不匹配 输出脱敏后的认证主体和权限,检查 matcher 顺序
预检 OPTIONS 失败 CORS 配置未在安全链正确处理 让 CORS 在 SecurityFilterChain 中生效,明确允许 Header/Method
Session 随机失效 多实例未共享 Session、负载均衡无粘性或 Cookie 配置错误 选择共享 Session 或无状态 Token,检查 SameSite/Secure/Domain
权限放开仍数据越权 只有功能权限,没有数据条件 在 Repository/Service 层强制租户和归属过滤

高频面试题

问题 回答要点
Spring Security 认证在哪发生? SecurityFilterChain 的认证过滤器将凭据交给 AuthenticationManager/Provider,成功后保存 Authentication 到 SecurityContext。
401 与 403 区别? 401 是未认证或认证无效,403 是已认证但无权限。
JWT 如何注销? 短 token + refresh token,或服务端维护会话版本/jti 黑名单;不能仅删除客户端 token。
CSRF 为什么主要影响 Cookie? 浏览器会自动携带 Cookie,攻击站点可诱导修改请求;Bearer Token 通常需脚本主动添加。
RBAC 足够吗? RBAC 管功能权限,订单、租户、部门等具体数据范围还需要数据权限。