Spring Boot 3 + Spring Security + OAuth2 + Gateway企业级认证授权平台实现

大家好,我是阿喵。

前两天在群里聊到微服务权限问题,不少朋友对 "网关层怎么做鉴权" 以及 "用户信息怎么在服务间无感传递" 非常头疼。之后, 我在小红书发布了一篇文章《Gateway+OAuth2 + JWT + RBAC实现动态鉴权》,然后看到有朋友想要代码。

微服务架构中,认证(Authentication)和鉴权(Authorization)是真正的"深水区"。很多网上的 Demo 只有简单的登录,涉及到跨服务调用(Feign)或者细粒度的方法级权限控制,全流程的很少。

我就基于 Spring Boot 3 + Spring Security + OAuth2 + Gateway 搭建了一套 RBAC 企业级认证授权平台 的过程整理了出来

不讲虚的,直接上干货!文末有完整源码获取方式。


01 为什么要这么设计?架构总览

在单体应用中,我们习惯用 Session;但在微服务容器化环境下,JWT(JSON Web Token) 才是无状态认证的最佳选择。

我们的核心架构设计思路如下:

  1. 统一入口(Gateway) :作为"保安",负责校验 JWT 的合法性,拦截非法请求。
  2. 独立认证(Auth Service) :发放"通行证"(Token),负责复杂的 OAuth2 流程。
  3. 业务解耦(Business Service) :业务服务不处理复杂的解密逻辑,只管"拿来即用"。
  4. 无感透传:利用 HTTP Header 和 ThreadLocal,让用户信息在链路中自由流转。

服务清单(基于 Spring Boot 3.2.4)

服务 端口 核心职责
gateway-service 8080 网关,GlobalFilter 全局鉴权
auth-service 9001 认证中心,颁发 JWT
business-service 9003 业务服务,演示 @PreAuthorize

02 核心难点一:网关层的"验票"逻辑

网关是流量的咽喉。如果每个请求都在这里查数据库,性能会直接崩盘。所以我们采用 JWT + 内存校验 的方式。

gateway-service 中,我们定义一个全局过滤器 JwtAuthFilter

Java

scss 复制代码
// 核心代码片段:网关过滤器
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    // 1. 拦截请求,提取 Token
    String token = extractToken(exchange.getRequest());
    
    // 2. 校验 Token 签名是否合法(纯内存操作,高性能)
    if (!jwtUtil.validateToken(token)) {
        return unauthorized(exchange); // 401
    }
    
    // 3. 关键一步:解析用户信息,放入请求头 Header 中
    // 这样下游服务就不需要再次解析 Token,直接读 Header 即可
    Claims claims = jwtUtil.parseToken(token);
    ServerHttpRequest mutatedRequest = exchange.getRequest().mutate()
        .header("X-User-Name", claims.getSubject())
        .header("X-User-Roles", claims.get("roles"))
        .build();
    
    return chain.filter(exchange.mutate().request(mutatedRequest).build());
}

思考:为什么这里用 WebFlux?

传统 Servlet 是线程阻塞模型,1000 个连接可能卡死 1000 个线程。而 Gateway 基于 Netty + WebFlux 响应式编程,少量线程即可处理海量并发,非常适合网关这种 IO 密集型场景。


03 核心难点二:用户信息流转(ThreadLocal 的妙用)

很多朋友会想问: "我在 Controller 里怎么拿到当前登录的用户 ID?"

难道要在每个方法参数里都写 String userId 吗?太 Low 了。

我们设计了一个三层流转模型

  1. 跨进程(网关 -> 服务) :使用 HTTP Header (X-User-Name) 传递。
  2. 进程内(Filter -> Controller) :使用 ThreadLocal(SecurityContext) 存储。
  3. 服务间(Feign 调用) :使用 FeignInterceptor 拦截器重新填入 Header。

下游服务的通用拦截器实现:

Java

scala 复制代码
@Component
public class GatewayAuthFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(HttpServletRequest request, ...) {
        // 1. 从 Header 读取网关透传过来的数据
        String username = request.getHeader("X-User-Name");
        
        // 2. 存入 ThreadLocal (SecurityContext)
        if (username != null) {
            UsernamePasswordAuthenticationToken auth = 
                new UsernamePasswordAuthenticationToken(username, null, authorities);
            SecurityContextHolder.getContext().setAuthentication(auth);
        }
        
        try {
            chain.doFilter(request, response);
        } finally {
            // 3. 必须清理!否则线程池复用会导致数据污染
            SecurityContextHolder.clearContext();
        }
    }
}

在业务代码中调用:

Java

less 复制代码
// 就像在单体应用一样简单
@GetMapping("/list")
@PreAuthorize("hasAuthority('goods:list')") // 注解鉴权
public List<Goods> list() {
    // 随处获取当前用户
    String currentUser = UserContext.getUsername(); 
    return service.findByUser(currentUser);
}

04 避坑指南(经验之谈)

在开发这套系统时,我踩过几个典型的坑,分享给大家:

  • Q: 为什么下游服务还要再写一遍 Filter?

    • A: 因为网关和下游服务是两个独立的 JVM 进程。网关的 ThreadLocal 传不到下游,只能通过 HTTP Header 作为桥梁。
  • Q: Feign 调用为什么会丢失用户信息?

    • A: Feign 默认发出的新请求是不带原始 Header 的。必须实现 RequestInterceptor,手动把 ThreadLocal 里的用户信息塞到 Feign 的请求头里。
  • Q: Spring Boot 3 的变化?

    • A: 以前的 javax.servlet 包全变成了 jakarta.servlet,Spring Security 6 的配置写法也大变样(废弃了 WebSecurityConfigurerAdapter),升级的时候要格外小心依赖版本。

05 源码领取 & 后续计划

微服务安全是一个庞大的话题,这篇通过 RBAC + JWT 搭建了一个标准骨架。

为了方便大家学习,我把:

  1. 完整的 SQL 脚本(包含用户/角色/权限表)
  2. Docker 部署说明
  3. 前后端联调 Postman 文件
  4. 四个微服务的完整源码

全部打包好了。

👉 获取方式:

关注公众号 喵了个Code,后台回复关键词 【Security实战】,即可获取 GitHub/Gitee 仓库地址。

🚀 下一步计划:

现在的配置还是稍显繁琐,我正在计划把这套逻辑封装成一个 Spring Boot Starter。未来大家只需要在 pom.xml 里引入一个依赖,就能自动拥有这套企业级鉴权能力!

如果你对"如何造轮子/写 Starter"感兴趣,欢迎点赞、在看,告诉我你想看!

相关推荐
开心猴爷3 小时前
除了 Perfdog,如何在 Windows 环境中完成 iOS App 的性能测试工作
后端
桦说编程4 小时前
简单方法实现子任务耗时统计
java·后端·监控
盖世英雄酱581364 小时前
物品超领取损失1万事故复盘(一)
java·后端
凌览5 小时前
别再死磕 Nginx!http-proxy-middleware 低配置起飞
前端·后端
拾玖不会code5 小时前
简单分表场景下的业务发散思考:分表如何保证丝滑?
后端
CryptoRzz5 小时前
印度尼西亚(IDX)股票数据对接开发
java·后端·websocket·web3·区块链
咕白m6255 小时前
通过 C# 快速生成二维码 (QR code)
后端·.net
踏浪无痕5 小时前
架构师如何学习 AI:三个月掌握核心能力的务实路径
人工智能·后端·程序员
小毅&Nora6 小时前
【后端】【SpringBoot】① 源码解析:从启动到优雅关闭
spring boot·后端·优雅关闭