微服务安全体系串讲
微服务的安全不是某个组件的事,而是一套分层体系:入口认证、权限控制、接口防篡改、传输加密、数据脱敏、攻击防护。本文把 Gateway 统一鉴权、RBAC、OAuth2、Spring Security、API 签名验签串成一条完整的安全链路。
安全体系全景
分层安全模型
微服务安全分层:
├─ 接入层:网关统一鉴权、限流、WAF
├─ 传输层:HTTPS / mTLS 加密
├─ 认证层:OAuth2 / JWT 身份认证
├─ 授权层:RBAC 权限控制
├─ 接口层:API 签名、防重放
├─ 数据层:脱敏、加密存储
└─ 应用层:Spring Security 细粒度控制安全设计原则
安全设计原则:
├─ 纵深防御:多层防护,不依赖单点
├─ 最小权限:只给必要的权限
├─ 默认拒绝:白名单思维
├─ 不信任输入:参数校验、防注入
└─ 可审计:关键操作留痕一、网关统一鉴权
为什么要网关统一鉴权
服务各自鉴权的问题:
├─ 重复实现(每个服务写一遍)
├─ 标准不统一(各服务鉴权逻辑漂移)
└─ 漏配风险(新增服务忘记加)
网关统一鉴权:
├─ 所有外部请求先进网关
├─ 网关做认证与粗粒度鉴权
└─ 内部服务间互信(或走 mTLS)Gateway 鉴权过滤器
java
@Component
public class AuthGlobalFilter implements GlobalFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
// 白名单放行(登录、回调等)
String path = request.getURI().getPath();
if (isWhitelist(path)) {
return chain.filter(exchange);
}
// 1. 取 Token
String token = request.getHeaders().getFirst("Authorization");
if (token == null || !token.startsWith("Bearer ")) {
return unauthorized(exchange, "缺少 Token");
}
// 2. 校验 Token(JWT 验签 / 调用认证中心)
try {
Claims claims = jwtUtil.parseToken(token.substring(7));
// 3. 解析用户信息放入请求头,透传下游
ServerHttpRequest mutated = request.mutate()
.header("X-User-Id", claims.get("userId").toString())
.build();
return chain.filter(exchange.mutate().request(mutated).build());
} catch (JwtException e) {
return unauthorized(exchange, "Token 无效或过期");
}
}
}网关鉴权职责
网关鉴权边界:
├─ 认证:Token 是否有效(身份)
├─ 粗粒度授权:路径级权限(如 /admin/** 需要管理员)
├─ 限流:防刷、防攻击
└─ 不做:业务级细粒度权限(数据归属校验在业务层)二、RBAC 权限模型
RBAC 模型
RBAC(基于角色的访问控制):
用户(User)→ 角色(Role)→ 权限(Permission)
├─ 用户分配角色
├─ 角色拥有权限
└─ 权限绑定资源操作
五张表:
├─ user(用户)
├─ role(角色)
├─ permission(权限)
├─ user_role(用户-角色关联)
└─ role_permission(角色-权限关联)权限数据模型
权限 = 资源 + 操作:
├─ 资源:订单、用户、商品
├─ 操作:增、删、改、查
├─ 权限编码:order:create、order:delete
└─ 角色:管理员拥有全部,运营拥有部分
示例:
管理员:user:*、order:*、product:*
运营: product:read、product:update、order:read
客服: order:read、user:read权限校验时机
RBAC 校验分层:
├─ 网关:URL 级粗粒度(路径 → 所需权限)
├─ 服务端:接口级(注解声明所需权限)
└─ 数据级:业务层校验数据归属(只能操作自己的数据)
服务端实现(注解 + 拦截器):
@PreAuthorize("hasAuthority('order:create')")三、OAuth2 与 Spring Security
OAuth2 认证流程
OAuth2 授权码模式(适合 Web/移动端):
1. 用户访问客户端 → 重定向到认证服务器登录
2. 认证服务器验证身份 → 返回授权码
3. 客户端用授权码换 Access Token
4. 客户端携带 Token 访问资源服务器
5. 资源服务器校验 Token 后返回资源微服务中的 OAuth2 落地:
├─ 认证服务器:统一登录、签发 Token(独立服务)
├─ 资源服务器:各业务服务校验 Token
└─ Token 格式:JWT(无状态,自包含用户信息)Spring Security + JWT
Spring Security 处理链:
├─ SecurityFilterChain 过滤器链
├─ 无状态 JWT 场景:
│ ├─ 关闭 Session
│ ├─ 自定义 JWT 认证过滤器
│ └─ 校验通过 → 填充 SecurityContext
└─ 授权:@PreAuthorize / hasRole / hasAuthority
JWT 结构:
├─ Header:算法与类型
├─ Payload:用户 ID、角色、过期时间
└─ Signature:私钥签名(防篡改)网关 + 认证中心 + 业务服务
认证体系分工:
├─ 认证中心(Auth Service):
│ ├─ 登录/登出、签发/刷新 Token
│ └─ 独立数据库存储用户与凭据
├─ 网关:
│ ├─ 校验 Token 有效性(调认证中心或本地验签)
│ └─ 填充用户信息头透传
└─ 业务服务:
├─ 信任网关透传的用户信息头(内网)
└─ 用 RBAC 做细粒度授权四、API 签名验签
为什么需要签名
签名解决的问题:
├─ 参数篡改:中间人改请求参数
├─ 身份伪造:伪造调用方
├─ 重放攻击:重复提交同一请求
└─ 场景:开放平台 API、服务间调用、关键接口
签名方案:
客户端 = 参数 + 时间戳 + 随机数 + 密钥 → 签名
服务端 = 同样的规则重算 → 比对签名算法流程
签名计算(示例:HMAC-SHA256):
1. 收集参数(业务参数 + 时间戳 + nonce)
2. 按 key 排序拼接(signString)
3. 用密钥 HMAC-SHA256 计算签名
4. 请求头携带:timestamp、nonce、sign
服务端校验:
1. 校验时间戳(防重放,如 5 分钟内有效)
2. 校验 nonce 是否已用过(Redis 记录,防重放)
3. 用密钥重算签名比对(防篡改)
4. 通过才处理业务java
public class SignUtil {
// 服务端校验签名
public static boolean verify(String params, String timestamp,
String nonce, String sign, String secret) {
// 1. 时间戳防重放:|now - timestamp| < 5min
if (Math.abs(System.currentTimeMillis() - Long.parseLong(timestamp)) > 300_000) {
return false;
}
// 2. nonce 防重放:Redis SETNX(已存在则拒绝)
if (!redis.setIfAbsent("nonce:" + nonce, "1", 300)) {
return false;
}
// 3. 重算签名比对
String expected = hmacSha256(params + timestamp + nonce, secret);
return expected.equals(sign);
}
}密钥管理
签名密钥管理:
├─ 每个调用方独立 AppKey/AppSecret
├─ 密钥存服务端,永不泄露
├─ 定期轮换
└─ 泄露可单独吊销(不影他其他调用方)五、常见攻击与防护
| 攻击类型 | 原理 | 防护 |
|---|---|---|
| SQL 注入 | 拼接 SQL 执行恶意语句 | 参数化查询、ORM、输入校验 |
| XSS | 注入恶意脚本窃取数据 | 输出转义、CSP、防 XSS 头 |
| CSRF | 伪造用户请求 | 校验 Token、SameSite Cookie |
| 重放攻击 | 重复提交合法请求 | 时间戳 + nonce + 幂等 |
| 暴力破解 | 试密码/试 Token | 限流、验证码、锁定策略 |
| DDoS | 大量请求打满资源 | 网关限流、WAF、CDN 防护 |
| 越权 | 访问他人数据 | 数据级权限校验(IDOR 防护) |
越权防护(重点)
越权类型:
├─ 水平越权:用户 A 访问用户 B 的数据
│ 例:GET /order/1001(校验 orderId 归属当前用户)
├─ 垂直越权:普通用户调管理员接口
│ 例:DELETE /admin/user(校验角色)
防护:
├─ 数据归属校验(业务层)
├─ 接口级权限注解
└─ 统一鉴权不遗漏新增接口六、数据安全
数据安全措施:
├─ 传输加密:全链路 HTTPS
├─ 敏感数据脱敏:手机号/身份证展示打码
│ └─ 139****1234
├─ 敏感数据加密存储:密码(BCrypt)、身份证(加密)
├─ 日志脱敏:日志中不打印完整敏感信息
└─ 合规:隐私数据授权、最小化收集七、安全体系完整链路
一次请求的安全旅程:
客户端
│ HTTPS 加密传输
▼
WAF / CDN(防 DDoS、Web 攻击)
│
▼
Gateway
├─ 限流(防刷)
├─ Token 校验(认证)
├─ 路径级权限(粗粒度授权)
└─ 透传用户信息头
│
▼
业务服务(Spring Security)
├─ 信任网关用户头
├─ @PreAuthorize 接口级权限(RBAC)
└─ 数据归属校验(防越权)
│
▼
数据库 / Redis / MQ
├─ 加密存储敏感数据
├─ 参数化查询(防注入)
└─ 审计日志(关键操作留痕)总结
微服务安全是一套分层协同的体系:网关统一认证与粗粒度授权,Spring Security 在服务内做细粒度 RBAC,OAuth2/JWT 解决身份与无状态认证,API 签名验签保障接口防篡改与防重放,再加数据脱敏、加密与攻击防护兜底。核心原则是纵深防御 + 最小权限 + 默认拒绝——每一层都独立可失效,不把安全寄托在单一环节上。