这里写目录标题
- 引言
- 1 安全性概括
- 1.1安全六要素
- 1.2微服务架构带来的安全性问题
- 拓展(可跳过)
- 2.权鉴设计
- 2.1概要
- 2.2权限控制模型
- RBAC模型
- 水平权限问题
- 权限模式总结
- 2.3授权协议
- OAuth2
- 核心概念
- 1. Access Token
- 2. Refresh Token
- 3. Scope
- 4. Grant Type
- 授权模式
- 其他模式
- OAuth2与RBAC/ABAC结合
- OAuth2缺陷
- token主动失效方案
- 使用短 token生命周期 + Refresh Token 撤销
- 总结
- 2.4 凭证
- 灵活的Token结构
- JWT
- Header
- Payload
- Signature
- 总结
引言
在本系列的前七篇博文中(第七篇有点长,拆成三篇但算一篇),我系统梳理了微服务架构作为分布式架构的一种形式,其在同步通信、客户端负载均衡、故障处理、网络路由以及事务管理等方面的设计原理。通过这一过程,我们不仅理解了这些核心机制的设计思路,还对微服务在 CAP 定理下的权衡有了初步认识。现在,我们距离全面掌握微服务架构的设计目标又近了一步。
然而,微服务架构的完整图景尚未浮现。一个自然而然的问题浮现出来:在设计微服务架构时,我们还需要考虑哪些关键因素?
答案显而易见——安全性设计。作为微服务架构不可或缺的一部分,安全性不仅是系统稳定运行的保障,也是保护数据和业务逻辑的重要防线。接下来,我们将深入探讨微服务架构中的安全性设计,补齐这一关键拼图。
1 安全性概括
1.1安全六要素
我们谈论系统安全,不仅仅是指“防御系统被黑客攻击”这样狭隘的安全,还至少应包括(不限于)以下这些问题的具体解决方案。
即 ,安全性六要素:
- 认证(Authentication):如何正确分辨出操作用户(服务)的真实身份?
一般通过凭证认证。 - 授权(Authorization):确定已认证的用户有哪些权限,能看到哪些数据,操作哪些功能?
授权通常涉及两个问题——“确保授权的过程可靠”、“确保授权的结果可控” - 凭证(Credential):用户或系统实体与系统交互时的“身份证明”。 既要可信,又要可证明。
凭证一般有用户密码、证书、Token等方式。 - 保密(Confidentiality):系统如何保证敏感数据无法被包括系统管理员在内的内外部人员所窃取、滥用?
如加密存储方式 - 传输(Transport Security):系统如何保证通过网络传输的信息无法被第三方窃听、篡改和冒充?
如HTTP - 验证(Verification):系统如何确保提交到每项服务中的数据是合乎规则的,不会对系统稳定性、数据一致性、正确性产生风险?
防范恶意输入,如进行参数校验、文件传输限制
其中“认证、授权、凭证”3者一般组合起来以权鉴(身份与权限管理)系统的形式存在,凭证用于认证,认证结果驱动授权。
而“保密、传输、验证”3者更多关注数据保护和操作安全,与权鉴系统互补。
这“六要素”不是某个标准文档的直接引用,但经过资料查找验证、总结。
例如信息安全领域的经典模型——CIA三要素:保密性(Confidentiality)、完整性(Integrity)、可用性(Availability)、认证性(Authenticity)、不可否认性(Non-repudiation)。
另外还有OWASP等……
六要素总结起来具备全面性、实用性、逻辑性。
思考架构的安全性设计前,我们先想一下,微服务架构较单体架构,其安全性有什么区别。
1.2微服务架构带来的安全性问题
当我们的服务还是单体架构时,其安全性考虑要简单的多。
此时的服务对外只有一个入口,网通通信时提供本身的IP、端口即可,外部请求访问可以统一处理(安全签名、参数校验、加密、白名单等安全操作)。
单体架构的权鉴和数据传输的安全性考虑也集中于对外入口。
即,
单体架构安全性聚焦外部威胁,防护集中与单一边界保护。
而微服务架构中,每个服务(或服务集群)都对外提供入口,服务间需要网络通信,数据需要跨服务传输,安全边界从“点”到扩展到“面”。
即,微服务架构的网络通信数量与入口大幅增加,安全设计需要覆盖的点也大幅增加了。
需构建“面面俱到”的防护体系,权鉴与数据传输从单一入口变成了分布式授权,数据保护与操作安全需要更全面,相关监控也需要考虑多个层面。防护措施管理复杂。
我们谨记“分布式运算的八宗罪之:网络是安全的”。
以及,网络不可靠带来的安全设计考虑。
拓展(可跳过)
这里也拓展总结一下分布式与单体架构的区别。
相较单体架构,分布式虽然带来了更高的灵活性、扩展性、高并发性能,以及更加低耦合、高内聚的可维护性,但是因为分散的存储、网络通信服务协作需求、服务共享需求,其也带来了复杂的系统设计与开发成本。
本系列的分布式诸多设计,原则上都是为了解决分布式的网络通信不可靠、数据共享问题。
从通信的第三方注册表到故障处理的熔断与降级,再到网络路由与分布式事务,还有负载均衡,都是从设计更可靠的网络通信与数据共享出发,而这一切都是为了 CAP,即一致性、可用性、容错可靠性。
而安全性设计也是同样围绕着分布式系统的网络不可靠、数据不共享问题,例如授权,在服务集群的服务实例 A 的授权结果是否可以当作整个服务集群都授权了,认证的过程是否可以一次认证处处使用?这些是独属于分布式的数据一致性与可用性问题。
而分布式安全性设计的核心问题就是如何做好设计,让安全性的六要素设计足够高效,满足分布式架构的拓展需求。毕竟不可能让每个服务都如同单体架构一样,每次请求都进行权限校验,分布式系统总归是共同的系统。
架构安全性有一个经验原则可以参考,即以标准规范为指导、以标准接口去实现。
2.权鉴设计
2.1概要
在大规模信息系统中,账户和权限的管理往往依赖专门的基础设施来实现,例如微软的活动目录(Active Directory,AD)或轻量目录访问协议(Lightweight Directory Access Protocol,LDAP)。这些系统通过集中化管理,提供统一的身份认证和权限分配功能。对于跨系统的共享需求,传统的单点登录机制(如 SAML、OAuth)已被广泛采用,而在一些前沿场景中,区块链技术也开始用于实现去中心化的身份和权限共享,确保数据安全与可信性。
即,为了避免每个服务重复实现认证和授权逻辑,为了持之大规模用户和服务,集中管理更高效,可拓展性更强。
在大型分布式架构中,安全性设计常常由第三方服务系统负责核心权鉴(如账户管理和凭证分发),其他服务通过集成这些系统实现认证和授权。
服务需承担凭证验证、本地授权和安全通信的责任,形成“集中管理 + 分布式执行”的模式。其中“本地授权”视情况而定,某些服务可能根据业务逻辑执行额外的权限检查。
这种模式平衡了集中管理的高效性和分布式系统的拓展性。
要实现“集中管理 + 分布式执行”的安全模式,我们需要借助权限控制模型,抽象出权鉴过程的核心环节,从而支持集中化的权限管理。
权限控制模型(如 RBAC、ABAC)提供了权限定义和分配的理论基础,而通过标准化权鉴流程(如认证和授权的统一接口),我们可以将权限管理集中于核心服务,同时将验证和执行分散到各个分布式节点。
2.2权限控制模型
在信息系统的安全设计中,认证和授权是身份与访问管理(IAM)的基石,而凭证则是连接这两者的关键工具。
三者共同协作,构成了权鉴体系的核心:认证负责验证身份的合法性,确保“谁是你”;授权定义权限的范围,决定“你能做什么”;凭证通过密码、token 或证书等形式,保障这一过程的安全性与可信度。
权鉴设计的本质,就是解决这样一个核心问题:“谁(User)拥有什么权限(Authority)去操作(Operation)哪些资源(Resource)”。
而这样的问题,有很多成理论体系的科学的权限管理机制,即“权限控制模型”。
这些权限控制模型有——自主访问控制 DAC(Discretionary Access Control)、强制访问控制 MAC(Mandatory Access Control)、基于属性的访问控制ABAC(Attribute-Based Access Control)、基于角色的访问控制RBAC(Role-Based Access Control)。
下面,让我们先来了解一下最常见的权限控制模型——RBAC模型。
RBAC模型
RBAC——基于角色的访问控制RBAC(Role-Based Access Control)
为了避免对每一个用户设定权限,RBAC将权限从用户身上剥离,改为绑定到“角色”(Role)上,将权限控制变为对“角色拥有操作哪些资源的许可”这个逻辑表达式的值是否为真的求解过程。
其中提出角色解耦了用户与权限直接的关联,将权限绑定到角色上。而提出许可的概念则将操作与资源的多对多关系解耦。
RBAC不仅简化了配置操作,还天然地满足了计算机安全中的“最小特权原则”(Least Privilege)。
在RBAC模型中,角色拥有许可的数量是根据完成该角色工作职责所需的最小权限来赋予的。
最典型的例子是操作系统权限管理中的用户组,根据对不同角色的职责分工,如管理员(Administrator)、系统用户(System)、验证用户(Authenticated User)、普通用户(User)、来宾用户(Guest)等分配各自的权限,既保证用户能够正常工作,也避免用户出现越权操作的风险。
水平权限问题
很容易理解,RBAC通过两次解耦,让权限集中在角色上。
这样的设计因为颗粒度还是很大,在实际应用场景中有会有一个“水平权限”问题,即“在同一角色或权限级别下,用户对具体资源实例的访问控制问题”。例如,限制用户只能访问“属于自己”的数据,而不是同角色下所有数据。
如果为每个有限制的用户创建独属角色,那么会有角色爆炸的问题。
RBAC为了解决“水平权限问题”扩展有RBAC1/RBAC2,如下:
- 层次 RBAC(RBAC1):
- 引入角色继承,定义更细化的角色(如“医生 A”继承“医生”),但仍可能导致角色爆炸。
- 约束 RBAC(RBAC2):
- 添加约束条件(如“只能访问自己的数据”),通过静态规则限制权限。
- 示例:在“医生”角色上加约束“患者.医生ID = 当前用户ID”。
或者结合基于属性的访问控制ABAC,如下:
- 属性扩展:
- 在 RBAC 中引入属性(如用户 ID、资源所有者),结合基于属性的访问控制(ABAC)。
- 示例:权限规则变为“角色 = 医生 AND 患者.医生ID = 用户.ID”。
- 优势:保持 RBAC 的角色管理优势,同时解决水平权限的动态性。
或者绑定其他的标识数据用以限制数据范围,如下:
- 定义范围:
- 为角色绑定数据范围(如“仅限自己的文档”),通过过滤器实现。
- 示例:数据库查询时自动附加“WHERE creator = :user_id”。
权限模式总结
总的来说,权限模型为分布式框架的“集中管理 + 分布式执行”模式的“集中管理”做了如下抽象:
RBAC将授权抽象成角色,分布式系统只需集中管理角色的定义和配置,即可实现对用户操作权限的统一控制。
那么,“分布式执行”又需要什么来实现呢?答案是授权协议。
2.3授权协议
分布式执行要求服务间通信标准化,授权协议提供了统一的凭证格式和验证流程,确保一致性和安全性。常见的多方授权协议主要有OAuth2和SAML2.0。
OAuth2
OAuth2 是一个授权框架(Authorization Framework),允许第三方应用程序以安全、可控的方式代表用户访问受保护资源,而无需共享用户密码。
通过标准化凭证(如Token),将集中定义的权限传递到各个服务,确保分布式节点能够独立验证和执行授权决策。
OAuth2 将用户认证(登录)和授权(同意)与 token 分发分开。
其核心特点是基于token,token代替直接传递密码,灵活,支持多授权场景,token可以在服务间传递,适合微服务架构。
OAuth2 定义了四个主要角色:
-
资源拥有者(Resource Owner):
- 通常是用户,拥有受保护资源(如你的 Google 邮件)。
-
客户端(Client):
- 请求访问资源的第三方应用(如某邮件客户端)。
- 需要注册到授权服务,获取 client_id 和 client_secret。
客户端开发者(通常是第三方应用的开发者)需要先在授权服务器上注册应用,获取一组凭证(client_id 和 client_secret)。这组凭证用于向授权服务器证明客户端合法性。
-
授权服务器(Authorization Server):
- 负责认证用户并发放 access token(如 Google 的 OAuth 服务)。
-
资源服务器(Resource Server):
- 存储受保护资源的服务器(如 Google 邮件服务器),接受 token 并验证。
核心概念
1. Access Token
- 定义:访问令牌,客户端用它访问资源服务器。
- 特性:
- 有限有效期(通常带 expires_in)。
- 可附加权限范围(scope,如“读邮件”)。
- 类型:常见为 Bearer Token(简单持有即可使用)。
2. Refresh Token
- 定义:刷新令牌,用于在 access token 过期后获取新 token。
- 用途:避免用户频繁重新登录。
通常有效期比 Access Token 长得多(如几天、几周甚至不限期),只能用于刷新Access Token。由后端结合client_id、client_secret向授权服务器/token发送刷新请求。
3. Scope
- 定义:权限范围,定义客户端能访问的具体资源或操作。
- 示例:scope=read_email write_email。
4. Grant Type
- 定义:授权流程的类型,决定客户端如何获取 token。
- 常见类型:
- 授权码模式(Authorization Code Grant):最常用,适合 Web 应用。
- 隐式模式(Implicit Grant):适合前端应用(如 SPA)。
- 密码模式(Resource Owner Password Credentials Grant):直接用用户名密码换 token,不推荐。
- 客户端凭证模式(Client Credentials Grant):服务间授权。
授权模式
其中授权码模式较为常见,流程如下:
-
1.第三方应用将资源所有者(用户)导向授权服务器的授权页面,并向授权服务器提供ClientID及用户同意授权后回调URI(redirect_uri)。即第一次客户端页面转向。
-
2.用户认证与授权。输入凭证并同意授权。
-
3.授权服务器并通过redirect_uri返回授权码code和用于验证请求来源的state。
获取授权码code作为中间步骤,获得的code是一个临时的、一次性的中间凭证,仅用于换区token。
OAuth2 这样设计等于将用户认证(登录)和授权(同意)与 token 分发分开。
授权码表示用户已完成认证和授权,但 token 分发是独立的步骤。
这允许授权服务器在发放 token 前再次验证请求(如检查 redirect_uri)。 -
4.客户端使用授权码code、client_id、client_secret向授权服务器发送请求获取access_token与refresh_token
其中client_id、client_secret这组凭证存在于后端,授权码code随请求同前端请求传递。前后端接口,解决了前端应用服务安全存储密钥(client_id、client_secret)的问题。
token 的实际分发通过客户端后端与授权服务器的直接通信(/token 请求)完成,避免 token 在不安全的浏览器环境中传递。 -
5.授权服务器返回token
-
6.客户端使用token访问资源服务器
-
7.资源服务器验证token并响应
UML时序图如下⬇️:
其他模式
-
隐式模式(Implicit Grant)
适用:无后端的前端应用(如单页应用 SPA)。
流程: 客户端直接请求 /authorize,response_type=token。 用户授权后,授权服务器通过 redirect_uri 返回 token(无 code 步骤)。 客户端用 token 访问资源。
特点:简单,但 token 暴露在浏览器中,安全性较低。 -
密码模式(Resource Owner Password Credentials Grant)
适用:受信任的客户端(如官方移动应用)。
流程: 客户端收集用户密码。 请求 /token,grant_type=password,附带用户名密码。 授权服务器返回 token。
特点:直接用密码换 token,不推荐(安全性差)。 -
客户端凭证模式(Client Credentials Grant)
适用:服务间授权(如微服务通信)。
流程: 客户端用 client_id 和 client_secret 请求 /token,grant_type=client_credentials。 授权服务器返回 token。 客户端用 token 访问资源。
特点:无用户参与,适合机器对机器。
OAuth2与RBAC/ABAC结合
OAuth2 本身不定义权限模型,而是通过 scope 和 token 提供扩展点,与 RBAC 或 ABAC 集成:
- RBAC:将角色(Role)嵌入 token,服务根据角色判断权限。
- ABAC:将属性(Attribute,如用户 ID、部门、环境)嵌入 token,服务根据属性动态决策。
而其中的关键工具,就是JWT。
- JWT(JSON Web Token) 是 OAuth2 中常用的 access token 格式,分为三部分:
- Header:元数据(如签名算法)。
- Payload:承载信息(如角色、属性)。
- Signature:签名,确保 token 未被篡改。
其中,Payload 可自定义,适合嵌入 RBAC 的角色或 ABAC 的属性。
- 嵌入角色
在 JWT 的 Payload 中添加自定义声明(claim),如 “roles”: [“admin”, “user”]。
或使用标准声明,如 “scope”: “admin user” 表示角色范围。
授权服务器查询RBAC系统,获取角色,将角色嵌入Token分发给客户端,然后资料服务器解析Token,依据角色判断权限。示例JWT如下:
//RBAC
{"sub": "user123", // 用户ID"iss": "auth.example.com", // 发行者"exp": 1698765432, // 过期时间"roles": ["admin", "user"] // 嵌入角色
}
ABAC与混合使用示例如下:
//ABAC
{"sub": "user123","iss": "auth.example.com","exp": 1698765432,"attributes": {"user_id": "123","department": "HR","location": "US","resource_owner": "user123"}
}
// 混合:RBAC+ABAC
{"sub": "user123","roles": ["employee"],"attributes": {"user_id": "123","department": "IT"}
}
OAuth2缺陷
在详细了解了OAuth2的授权模式后,我们能发现其设计中并没有让token主动失效的设计。
在计算机系统中,“无状态”(Stateless)是指服务器在处理请求时,不依赖于之前的请求状态或会话信息。每个请求都包含足够的信息,服务器可以独立完成处理,而无需查询额外的上下文或存储的状态数据。
OAuth2便是无状态设计,无状态性主要体现在Access Token的设计和使用上,持有者即有效。客户端在请求资源时,只需要在请求中附上token,无需额外验证身份。
这样的无状态设计是分布式友好的,可以实现“分布式执行”,资源服务器可以本地验证token,无需网络调用,响应更快。
但也因为 token 无状态,授权服务器无法在到期前撤销它。token 存在泄漏风险,一旦泄漏,持有者即可使用,无需额外验证。而且当用户权限调整时,旧 token 仍保留原有权限。
token主动失效方案
使用短 token生命周期 + Refresh Token 撤销
- 思路:
- 将 Access Token 的有效期设置得很短(如 5-15 分钟)。
- 客户端依赖 Refresh Token 频繁刷新获取新 token。
- 若需失效,授权服务器拒绝刷新请求。
- 用户登出或权限变更时,撤销 Refresh Token,短生命周期的 Access Token 很快失效。
- 实现:
- 授权服务器存储 Refresh Token(如数据库或缓存)。
- 提供 /revoke 端点,客户端提交 refresh_token 撤销。
- 示例请求:
POST /revoke
Content-Type: application/x-www-form-urlencoded
token=rt-abc123-xyz789
token_type_hint=refresh_token
client_id=abc123
client_secret=xyz789
- 优点:
- 平衡安全与性能。
- 符合 OAuth2 扩展(如 RFC 7009)。
- 缺点:
- 需要额外的撤销支持。
总结
授权协议如OAuth2,通过标准化token(标准化凭证),解决了分布式架构安全性的“分布式执行问题”。
各服务接收 token,独立验证(如用公钥检查签名),无需实时查询授权服务器。
其中的授权码code设计解决了浏览器直接从授权服务器获取 token 的不安全问题。
具体而言,一是避免了 token 在浏览器地址栏或网络中暴露而被拦截的风险;二是通过后端交换 token,确保 client_secret 在安全环境下使用,而非暴露在浏览器中。
这种分离设计将授权(生成 code)与 token 分发(后端请求)分开,虽然增加了一次后端调用,但这是授权码模式提升安全性的核心机制。
2.4 凭证
从OAuth2结合权限模型的方式我们很容易得知,在OAuth2协议中的token是可以被嵌入各种信息以达成权限模型设计目标的。
Token具体是怎么设计的呢?JWT(JSON Web Token)又是怎么成为最广泛使用的令牌格式的呢?
灵活的Token结构
Token 本身不限定格式,可以是简单的字符串,也可以是结构化的数据(如 JWT)。通过嵌入信息,Token 可以承载权限模型所需的各种数据(如角色、属性)。
JWT
以OAuth2常用的JWT(JSON Web Token) 为例,JWT结构化、可拓展、能嵌入信息。其由三部分组成,用 . 分隔。
- Header(标头)
- Payload(有效载荷 )
- Signature(签名)
因此,JWT通常为xxxxx.yyyyy.zzzzz
Header
标头通常由两部分组成:令牌的类型,即 JWT,以及所使用的签名算法,例如 HMAC SHA256 或 RSA。
{ "alg": "HS256", "typ": "JWT"
}
Header这个 JSON 被Base64Url编码以形成 JWT 的第一部分。
Payload
令牌的第二部分是有效负载,其中包含声明。声明是关于实体(通常是用户)和附加数据的声明。声明分为三种类型:registered(注册声明)、public(公共声明)和private(私人声明).
{"sub": "1234567890","name": "John Doe","admin": true
}
Payload这个 JSON 被Base64Url编码以形成 JWT 的第二部分。
Signature
要创建签名部分,您必须采用编码标头、编码有效负载、秘码、标头中指定的算法,然后对其进行签名。
例如,如果要使用 HMAC SHA256 算法,将按以下方式创建签名:
HMACSHA256(base64UrlEncode(header) + "." +base64UrlEncode(payload),secret)
即使用·分割三个 Base64-URL 字符串。
最终的JWT如下:
![[Pasted image 20250401113837.png]]
总结
Token 的本质是 OAuth2 中的授权凭证,用于承载用户的权限信息。
其中,JWT(JSON Web Token)在信息承载方面表现出色,其设计紧凑,编码体积小却能容纳丰富的有效信息。相比其他方式(如 SAML),JWT 的结构更加精简,编码大小显著减小。
它通过 Payload 或 scope 灵活嵌入权限数据,支持多种权限模型(如 RBAC、ABAC)。
此外,JWT 提供多种加密和签名选项(如 HMAC、RSA),增强了安全性。
由于 JSON 格式解析器在大多数编程语言中广泛支持,并能直接映射到对象,JWT 的处理极为高效。这种特性使其特别适合分布式执行环境,在多服务协同运行的场景中展现出更大的便利性和适配性。