安全与认证鉴权
Java 架构师 · 安全 · 调优 · AI · 前沿
安全是架构的"地基"。认证(你是谁)、授权(你能做什么)、数据安全(敏感不泄露)三者缺一不可。架构师的核心任务是:在网关与微服务间建立统一的身份传播与最小权限体系,并把"纵深防御"与"假设被攻破"作为默认思维。本章深入 OAuth2.0 四种授权模式、JWT 无状态校验、Spring Security 过滤器链,以及数据脱敏与合规落地。
一、安全三要素与分层
- 认证(Authentication):验证主体身份(你是谁)。常用 OAuth2.0(授权框架)+ JWT(令牌载体)。
- 授权(Authorization):基于角色(RBAC)或属性(ABAC)控制资源访问(你能做什么)。
- 数据安全:传输加密(TLS)、存储加密(AES/KMS)、脱敏、审计。
- 纵深防御:网关、服务、数据任何一层都可能被攻破,需多层校验 + 审计日志,不依赖单点。
二、OAuth2.0:四种授权模式
OAuth2.0 是解决"第三方如何在用户授权下访问资源"的框架。四种模式各有适用边界:
| 模式 | 适用 | 流程要点 | 风险 |
|---|---|---|---|
| 授权码(Authorization Code) | 有后端的 Web 应用(最安全) | 先拿 code 再换 token(code 短命、可 PKCE) | 需防 code 拦截 |
| 授权码 + PKCE | 公开客户端(SPA/移动端) | 无 client_secret,用 code_challenge 防拦截 | 最推荐的公客户端方案 |
| 客户端凭证(Client Credentials) | 服务间(Machine-to-Machine) | 直接用 client_id/secret 换 token | 无用户上下文 |
| 密码(Resource Owner Password) | legacy/高度信任 | 用户直传账号密码给客户端 | 不推荐(泄露密码) |
| 隐式(Implicit) | 已废弃 | token 直接返前端 | 暴露 token,弃用 |
授权码模式为何最安全:token 不在浏览器/重定向里暴露(只传短命 code),且支持 PKCE 防 code 拦截。资源服务器校验 access_token(JWT 自包含签名,无需每次在线查授权服务器),实现无状态。
三、JWT:无状态令牌的校验
JWT 结构 Header.Payload.Signature:
- Header:算法(HS256/RS256)、类型。
- Payload:
sub(用户)、scope(权限)、exp(过期)、aud等声明(claims)。 - Signature:用密钥/私钥对前两部分签名,防篡改。
无状态校验:资源服务器用公钥(RS256)或共享密钥(HS256)验证签名 + 过期,无需访问授权服务器 → 横向扩展无状态。但 JWT 不可撤销(除非短 exp + 吊销列表),且 Payload 仅 Base64 编码(可被解码,绝不可放密码/证件号)。
Spring Security + JWT 资源服务器:
@Bean
SecurityFilterChain chain(HttpSecurity http) throws Exception {
return http
.authorizeHttpRequests(a -> a
.requestMatchers("/actuator/**").permitAll()
.requestMatchers("/api/admin/**").hasRole("ADMIN") // 细粒度授权
.anyRequest().authenticated())
.oauth2ResourceServer(o -> o.jwt(j -> j.decoder(jwtDecoder()))) // 验签+过期
.csrf(csrf -> csrf.disable()) // 无状态 API 关闭 CSRF(用 token 而非 cookie)
.build();
}JWT 的四大陷阱
- 不过期/长有效期:泄露即长期可用。必须短
exp(如 15min)+ 刷新令牌(refresh_token,可吊销)+ 吊销列表(黑名单/版本号)。 - 敏感信息入 Payload:JWT 可被解码,密码/证件号严禁入 Payload(只能放非敏感标识与权限)。
- 密钥管理弱:HS256 共享密钥泄露 = 可伪造任意 token;用 RS256(私钥签名、公钥验)更安全,密钥托管 KMS。
- 无吊销机制:token 被盗用无法即时失效。需 refresh token 黑名单 / token 版本号(用户改密则旧版本号失效)。
四、Spring Security 过滤器链
Spring Security 本质是一条过滤器链(Filter Chain),请求依次经过:
ChannelProcessingFilter(HTTPS 强制)SecurityContextPersistenceFilter(恢复/清空安全上下文)UsernamePasswordAuthenticationFilter/BearerTokenAuthenticationFilter(认证,构建 Authentication)AuthorizationFilter(鉴权,按规则放行/拒绝)- 异常处理、
LogoutFilter等。
每个 Filter 要么把 Authentication 放进 SecurityContext,要么抛异常(403/401)。架构师要理解:认证在链前段、授权在链后段;自定义逻辑(如从网关可信头取用户)可插入自定义 Filter 或 AuthenticationManager。
五、网关与服务的职责划分
- 网关:统一身份认证(校验 JWT 签名/过期),把可信身份(如
X-User-Id、X-Roles)通过内部头传给下游。下游信任网关注入的头(内网可信)。 - 服务:做细粒度授权(如"用户 A 能否改订单 B"——必须校验订单归属,网关不知道业务归属)。
鉴权只在网关做 = 越权漏洞
网关只能证明"你是登录用户",不知道"这条订单是不是你的"。若服务不校验归属,攻击者可改 URL 里的 orderId 操作他人订单(IDOR 越权)。细粒度授权必须下沉服务层:基于资源 owner 校验 + 基于数据的 ABAC 策略。
六、数据脱敏与合规
- 传输:全链路 TLS(HTTPS/mTLS),禁止明文令牌传输被截获。
- 存储加密:敏感字段 AES 加密入库,密钥托管 KMS(轮换 + 不落代码)。
- 脱敏:日志/返回中手机号
138****8000、身份证****、token掩码。前端展示按权限决定完整/脱敏。 - 审计:关键操作留痕(谁、何时、改了什么),满足等保/个保法。
- 最小权限:默认拒绝(deny by default),按需授权;敏感操作二次认证。
本节小结
安全三要素:认证确认身份、授权控制权限、数据保障隐私。OAuth2.0 四种模式中,授权码+PKCE 是最安全推荐方案(token 不暴露、防拦截),客户端凭证用于服务间、密码模式应避免。JWT 用签名防篡改、用公钥验签实现无状态,但短 exp + 可吊销是必须的(Payload 可解码、不可放敏感)。Spring Security 是一条过滤器链:认证在前、授权(hasRole/scope)在后。关键架构原则:网关统一认证、服务做细粒度授权(防 IDOR 越权)、全链路 TLS、数据加密 + 脱敏 + 审计、最小权限。架构师要把"纵深防御"与"假设被攻破"作为默认思维。
📚 官方文档与参考资料
- Spring Security 参考文档:https://docs.spring.io/spring-security/reference/
- OAuth 2.0 规范(官方):https://oauth.net/2/
- JWT 介绍(结构/校验):https://jwt.io/introduction
- OAuth 2.0 PKCE(公开客户端安全):https://oauth.net/2/pkce/
✏️ 练习与自测
- 设计题:设计一个"用户只能查看自己订单"的授权方案,说明网关(认证 + 注入身份头)与服务(校验订单归属)各负责什么,并画出防 IDOR 越权的校验流程。
- 设计题:JWT 被盗用后如何实现"紧急吊销"?对比黑名单(jti 表)与令牌版本号(用户改密失效)两种方案的优劣与实现。
- 辨析题:为什么 OAuth2.0 的密码模式不推荐、隐式模式已废弃?在你们的移动端 App 中,应该用哪种模式 + PKCE?说明理由。
- 设计题:给出接口层的敏感数据脱敏清单(哪些字段、哪些场景必须脱敏——日志/列表/详情/导出),并说明密钥如何托管(KMS)而非硬编码。