首先感谢你把这么枯燥的技术选型问题坚持看到了这里。这篇文章不是官方文档的复读,而是我在微服务改造过程中,把Spring Cloud体系下分布式权限校验从零到一完整落地的一份经验沉淀。如果你正在被跨服务session共享、网关认证、方法级权限控制这些问题折腾,可以直接照着这套思路去盘。
开篇先回答一个最常见的问题:为什么单体时代好好的权限校验,一拆成微服务就处处碰壁?这个根子上的问题不想明白,后面接OAuth、JWT、网关过滤器都会觉得是在盲目堆技术。
1. 先想清楚:分布式权限校验到底在解决什么问题
1.1 单体时代的权限校验,为什么在微服务里撑不住
传统的单体应用普遍走Spring Security加Session这套组合拳。用户登录成功之后,session状态保存在服务端内存里,浏览器通过Cookie里的sessionId关联到这份状态。单体只有一个进程,所有功能模块共享同一份内存,权限校验时直接通过session拿用户信息即可,简单可靠,也没有分布式带来的网络开销。
然而微服务拆分之后,用户请求要经过API网关,再转发到用户服务、订单服务、库存服务等不同进程。session到底存在哪里?如果只存在某一个服务,其他服务怎么知道当前用户是谁?大家最先想到的往往是session复制、粘滞会话、共享session存储这老三样,但每一条路走深了都有坑。
- Session复制:在集群内把session广播到所有实例,实例一多,同步延迟和网络带宽都是问题,而且每次请求还要找正确的session版本。
- 粘滞会话:负载均衡器按用户维度把请求固定到一台实例,确实能访问到本地session,但实例重启或宕机时,上面所有用户的会话全部失效,轻则重新登录,重则影响正在进行的业务操作。
- 共享Session存储:把session统一存到Redis,思路是对的,但需要改造session的存取机制,还要处理序列化、过期、并发等细节。更关键的是,这种方式会把所有服务重新绑定到一个集中的会话状态上,和微服务独立部署、独立扩展的初衷有很大冲突。
所以单体时代的方案并不是不能做分布式改造,而是改来改去都绕不开“会话状态共享”这个死结。只要状态是共享的,服务之间的耦合就在,故障半径就大,扩容也受限制。
1.2 换个思路:从“保存状态”变成“携带状态”
既然共享session这么麻烦,那不如换一个方向:服务端不保存登录状态,而是给客户端发一个令牌,令牌本身携带用户的标识、有效期、权限范围。客户端每次请求都带上这个令牌,服务端只负责验签和解析,不需要在内存或者Redis里记录“这个用户是否在线”。
这就是无状态认证的基本思路。令牌的格式有很多种,最常被拿来做对比的是普通随机字符串和JWT:
- 普通随机字符串令牌:服务端签发一个UUID给客户端,然后在Redis里存一份映射表,记录这个UUID对应的用户和过期时间。这种方案本质上还是有状态,因为服务端必须保存令牌和用户的关系。
- JWT令牌:把用户ID、过期时间、权限范围等信息经过签名编码到令牌本身,服务端拿到令牌后用公钥验签,签名合法就信任token里的claims。这就是真正的无状态。
从工程角度看,JWT特别适合微服务场景,因为验签动作可以在网关层并发完成,业务服务只需要信任网关透传过来的用户信息,或者自己再做一次轻量验签,根本不需要每次请求都访问一次共享存储。网关集群里的任何一台机器都能独立完成校验,天生支持水平扩展。
1.3 OAuth 2.0解决的不只是“登录”,更是“授权边界”
很多初学者会把OAuth理解成“一种登录方式”,严格来说并不准确。OAuth 2.0是一套授权框架,它解决的问题是:一个客户端应用在资源所有者授权之后,如何安全地获取访问受保护资源的令牌。它把“登录认证”和“授权访问”做了明确区分。
在微服务架构里,OAuth的价值尤其明显。它把签发令牌的动作收敛到授权服务器,令牌的校验动作下放到各个资源服务。前端App不再到处传递用户名密码,而是统一到授权服务器换token;业务服务只认token,不关心前端是怎么登录的。
我自己早年也图省事,写过简单的token工具类,用Redis保存token映射关系,看起来也能跑。可一旦遇到多客户端接入、有效期管理、刷新令牌、权限审计、第三方系统对接这些需求,自研方案就会越改越复杂。切换到OAuth标准之后,这些能力全是现成的,团队沟通成本低,后续扩展也顺畅。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. OAuth 2.0核心概念与方案选型
2.1 四个角色,先在心里搭一个模型
OAuth 2.0定义了四个基础角色,理解它们就能看懂整套协议,也能知道自己在微服务里该把代码放到哪里。
- 资源所有者:拥有受保护资源的人或者系统,在业务系统里通常就是用户。
- 客户端:需要访问资源所有者的受保护资源的应用,可以是Web应用、移动App,也可以是另一个微服务。
- 授权服务器:负责验证资源所有者的身份并颁发访问令牌,相当于独立出来的认证中心。
- 资源服务器:托管受保护资源的服务,在微服务架构里就是订单服务、用户服务、库存服务这些业务系统。
拿电商网站举例。用户打开App点“登录”,App作为客户端把用户引导到授权服务器;授权服务器校验用户名密码,用户确认授权后,授权服务器给App一个授权码;App拿着授权码向授权服务器换访问令牌;之后App带着令牌请求订单服务,订单服务验签通过才返回订单数据。
这里最关键的设计是:用户的账号密码全程只经过授权服务器,客户端和业务服务都接触不到密码。这样可以大大缩小密码泄露的攻击面,也是OAuth在安全性上优于裸token的地方。
2.2 四种授权模式,该选哪一种
OAuth 2.0根据客户端类型和使用场景,定义了四种授权模式。选错模式是很多项目后续越改越痛苦的根源,这里我把适用场景说清楚。
- 授权码模式:安全性最高,流程最完整,适合有后端服务的前端应用。用户在前端登录后,授权服务器先返回授权码,后端用授权码再换token,token不经过浏览器,最大程度避免暴露。
- 隐藏式模式:适合纯前端单页应用,直接以URL片段方式返回token。实现简单,但token可能被浏览器历史记录、第三方脚本截获,OAuth社区现在普遍不推荐,主流做法是仍然由后端代理完成授权码流程。
- 密码模式:客户端直接拿用户名密码换token,实现最快,但客户端保存用户密码,安全性依赖客户端的可信程度。官方文档并不特别推荐,但在高度可信的内部系统中仍然可以见到。
- 客户端模式:没有用户概念,客户端以自身凭证去授权服务器申请token,代表客户端自己访问资源。适合服务间调用、定时任务、后台批处理这些机器对机器的场景。
微服务权限改造的选型建议很直接:面向用户的Web应用优先走授权码
