Spring Cloud Gateway + Sa-Token 1.34.0:一个全局过滤器搞定微服务统一鉴权(附完整代码)
·
Spring Cloud Gateway 与 Sa-Token 深度整合:全局过滤器实现微服务统一鉴权实战
在微服务架构中,API 网关作为系统入口,承担着路由转发、流量控制和安全防护等重要职责。其中,鉴权功能的统一处理尤为关键——它既要保证安全性,又要避免在每个微服务中重复实现。本文将深入探讨如何通过 Spring Cloud Gateway 的全局过滤器机制,与轻量级权限框架 Sa-Token 无缝集成,构建一套高效、灵活的微服务统一鉴权方案。
1. 技术选型与架构设计
1.1 为什么选择 Sa-Token?
Sa-Token 作为一款国产轻量级权限认证框架,相比传统方案(如 Spring Security)具有显著优势:
- 学习曲线平缓 :API 设计直观,文档详尽,新手可在 1 小时内上手基础功能
- 功能完备 :支持登录认证、权限验证、角色校验、会话管理等高阶特性
- 微服务友好 :提供专门的反应式编程支持(sa-token-reactor-spring-boot-starter)
- 灵活扩展 :所有核心组件均可自定义实现,满足企业级定制需求
// 典型Sa-Token权限检查示例
@GetMapping("/user/info")
public SaResult getUserInfo() {
// 检查是否登录(未登录会抛出异常)
StpUtil.checkLogin();
// 检查权限(无权限会抛出异常)
StpUtil.checkPermission("user.query");
// 执行业务逻辑
return SaResult.data(userService.getInfo());
}
1.2 网关层鉴权架构
在微服务场景下,我们推荐采用"网关统一鉴权 + 微服务透传用户标识"的架构模式:
- 网关层 :处理所有入口请求的认证和基础权限校验
- 业务服务 :仅需关注业务权限校验(如数据级权限)
- 认证服务 :独立部署,负责登录/注销等核心认证逻辑
这种分层设计带来三个核心优势:
- 安全性集中管理 :所有请求必经网关校验,避免安全漏洞
- 业务解耦 :微服务无需关注认证逻辑,降低复杂度
- 性能优化 :网关层可缓存权限信息,减少重复校验开销
2. 核心实现:全局过滤器配置
2.1 基础依赖配置
首先确保网关服务引入必要依赖(以 Maven 为例):
<!-- Spring Cloud Gateway -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
<version>3.1.3</version>
</dependency>
<!-- Sa-Token Reactor支持 -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-reactor-spring-boot-starter</artifactId>
<version>1.34.0</version>
</dependency>
<!-- Redis集成(用于会话存储) -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-dao-redis-jackson</artifactId>
<version>1.34.0</version>
</dependency>
2.2 SaReactorFilter 深度配置
全局过滤器的核心实现主要围绕 SaReactorFilter 展开,以下是一个生产级配置示例:
@Configuration
public class GatewayAuthConfig {
@Bean
public SaReactorFilter saReactorFilter() {
return new SaReactorFilter()
// 拦截所有路径
.addInclude("/**")
// 排除静态资源
.addExclude("/favicon.ico", "/static/**")
// 设置认证逻辑
.setAuth(obj -> {
// 登录检查:排除登录接口
SaRouter.match("/**")
.notMatch("/auth/login")
.check(r -> StpUtil.checkLogin());
// 权限检查:动态路由配置
SaRouter.match("/order/**", r -> StpUtil.checkPermission("order"));
SaRouter.match("/user/**", r -> StpUtil.checkPermission("user"));
// 角色检查:管理员专属接口
SaRouter.match("/admin/**", r -> StpUtil.checkRole("admin"));
})
// 异常处理
.setError(e -> {
log.error("网关鉴权异常", e);
return SaResult.error("认证失败:" + e.getMessage());
});
}
}
关键配置项说明:
| 配置项 | 说明 | 示例值 |
|---|---|---|
| addInclude | 需要拦截的路径 | /** (全部路径) |
| addExclude | 排除路径(白名单) | /auth/login , /public/** |
| setAuth | 认证逻辑 | 包含登录、权限、角色检查 |
| setError | 异常处理 | 统一返回格式 |
2.3 动态权限控制实践
对于更复杂的权限场景,建议实现动态路由配置:
// 从数据库加载权限配置
List<Permission> permissions = permissionService.listAll();
permissions.forEach(perm -> {
SaRouter.match(perm.getPath(), r -> {
if (perm.getType() == 1) {
StpUtil.checkPermission(perm.getCode());
} else {
StpUtil.checkRole(perm.getCode());
}
});
});
配合缓存机制,这种实现既保持灵活性,又不会对性能造成显著影响。
3. 高级特性与性能优化
3.1 多级缓存策略
鉴权性能直接影响网关吞吐量,推荐采用三级缓存方案:
- 本地缓存 :使用 Caffeine 缓存高频访问的权限数据(有效期 1-5 分钟)
- Redis 缓存 :存储全量权限数据(有效期 30 分钟)
- 数据库 :权限变更时主动刷新缓存
// 自定义权限加载实现(带缓存)
@Component
public class CustomStpInterface implements StpInterface {
@Cacheable(value = "user-permissions", key = "#loginId")
@Override
public List<String> getPermissionList(Object loginId, String loginType) {
return permissionMapper.selectByUserId(loginId);
}
}
3.2 灰度发布支持
在权限系统升级时,可通过 Header 标记实现灰度控制:
SaRouter.match("/**")
.header("X-Auth-Version", "v2")
.check(r -> StpUtil.checkPermission("new_permission"));
3.3 监控与指标
集成 Micrometer 暴露鉴权指标:
@Bean
public MeterRegistryCustomizer<MeterRegistry> metricsCommonTags() {
return registry -> registry.config().commonTags(
"application", "gateway",
"auth-system", "sa-token"
);
}
关键监控指标包括:
- 认证请求总数
- 认证失败率
- 权限检查平均耗时
- 令牌验证QPS
4. 生产环境最佳实践
4.1 安全加固措施
- 令牌防篡改 :启用
token-style配置为uuid增强安全性 - HTTPS 强制 :在网关层配置自动跳转 HTTPS
- 频率限制 :对登录接口添加限流(如 10次/分钟)
# application.yml 安全配置
sa-token:
token-name: satoken
timeout: 1800
token-style: uuid
is-share: true # 微服务间共享token
4.2 常见问题解决方案
问题1:跨服务权限失效
解决方案:
- 确保所有服务使用相同的
token-name配置 - Redis 配置相同的数据库索引
- 检查系统时间是否同步
问题2:性能瓶颈
优化建议:
- 增加
sa-token.timeout减少频繁校验 - 使用
@SaCheckOr合并多个权限检查 - 对公共接口添加
@SaCheckDisable注解
4.3 调试技巧
开发阶段可启用详细日志:
# logback-spring.xml
<logger name="cn.dev33.satoken" level="DEBUG"/>
<logger name="org.springframework.cloud.gateway" level="TRACE"/>
关键日志信息包括:
- 令牌解析过程
- 权限匹配路径
- 过滤器执行顺序
在网关层实现统一鉴权后,业务微服务只需关注核心业务逻辑,通过上下文获取用户标识即可:
@GetMapping("/profile")
public UserProfile getProfile() {
long userId = StpUtil.getLoginIdAsLong();
return profileService.getByUserId(userId);
}
更多推荐


所有评论(0)