单点登录、OAuth、OIDC原理过程区别
文章目录
- 单点登录、OAuth、OIDC原理过程区别
- 单点登录概念
- 优点
- 什么是 OAuth?
- 概述
- OAuth 2.0 中的角色
- 客户端类型
- 客户端注册
- 抽象协议流程
- 协议流程图
- Authorization Grant (授权许可)
- Access Token (访问令牌)
- Refresh Token (刷新令牌)
- OpenID
- 概述
- OpenID Connect (OIDC)
- OIDC 中的角色
- OpenID Connect协议有三种类型
- Authorization Code Flow (授权码模式) 流程
- 1. 准备授权请求(Prepare Authorization Request)
- 2. 授权请求(Authorization Request)
- 3. 验证用户身份(Authenticate End User)
- 4. 用户授权(Consent/Authorization)
- 5. 重定向返回授权码(Redirect with Authorization Code)
- 6. 接收授权码(Receive Authorization Code)
- 7. 令牌请求(Token Request)
- 8. 返回 Access Token 和 ID Token
- 9. 验证 ID Token(Validate ID Token and Get End User Subject Identifier)
- 10. 可选的 Access Token 使用(Optional Access Token Usage)
- 11. 可选的 UserInfo 响应(Optional UserInfo Response)
- 关键技术要求
- Implicit Flow(隐式模式)流程
- 流程步骤
- **1. 依赖方准备授权请求**
- **2. 终端用户发送授权请求**
- **3. 授权服务器鉴别终端用户**
- **4. 终端用户同意授权**
- **5. 授权服务器重定向回依赖方**
- **6. 依赖方接收 ID 令牌和访问令牌**
- **7. 依赖方验证 ID 令牌**
- **8. (可选)依赖方使用访问令牌访问受保护资源**
- **9. (可选)UserInfo Response**
- 请求:
- 响应:
- **完整流程总结**
- 关键特点
- 隐式模式的主要安全挑战
单点登录概念
一次用户的身份鉴别动作(唯一的身份注册)
- 登录多个系统
- 不需要反复多次的输入password
- 可能包含了多次的“系统自动化动作”
优点
- 简化用户操作
- 简化管理
- 集中式的、统一安全策略
- 重置口令的请求,大量减少
什么是 OAuth?
概述
- OAuth 2.0 是一个授权框架:
- 允许第三方应用获得对网络服务的有限访问权限。
- 第三方应用可以:
- 代表资源所有者,通过协调资源所有者与 HTTP 服务之间的批准交互来获得访问权限;
- 或者以自己的名义获得访问权限。
- 无需暴露用户的凭据。
OAuth 2.0 中的角色
- 资源所有者 (Resource Owner):
- 能够授予对受保护资源访问权限的实体。
- 当资源所有者是人时,称为终端用户 (end-user)。
- 资源服务器 (Resource Server):
- 托管受保护资源的服务器,能够使用访问令牌接收和响应对受保护资源的请求。
- 客户端 (Client):
- 一个应用程序,代表资源所有者并在其授权下发起受保护资源请求。
- 授权服务器 (Authorization Server):
- 在成功验证资源所有者并获得授权后,向客户端颁发访问令牌的服务器。
客户端类型
-
Web 应用程序是一个运行在网络服务器上的机密客户端。
- 客户端凭据以及颁发给客户端的任何访问令牌都存储在网络服务器上,且不会暴露给资源所有者或被其访问。
- 客户端凭据以及颁发给客户端的任何访问令牌都存储在网络服务器上,且不会暴露给资源所有者或被其访问。
-
基于用户代理的应用程序是一个公共客户端,客户端代码从网络服务器下载,并在资源所有者使用的设备上的用户代理(例如,网络浏览器)中执行。
- 例如,在浏览器中运行的 JavaScript 应用程序。
- 例如,在浏览器中运行的 JavaScript 应用程序。
-
本地应用程序是安装在资源所有者所使用设备上的公共客户端,并在该设备上执行。
- 协议数据和凭据对资源所有者是可访问的。
- 例如,安装在用户计算机或设备(如手机、平板电脑)上的应用程序。
客户端注册
- 在启动协议之前,客户端需要向授权服务器注册。
- 客户端开发者需要:
- 指定客户端类型。
- 提供客户端的重定向 URI。
- 授权服务器:
- 向注册的客户端分配一个客户端标识符。
- 为机密客户端建立认证方法,通常颁发一套客户端凭据(如密码、公钥/私钥对)。
- 可以为公共客户端建立认证方法。
- 客户端注册的方法不在 RFC6749 的范围内。
抽象协议流程
协议流程图
- (A) Authorization Request(授权请求) -> 资源所有者 (Resource Owner)
- (B) Authorization Grant(授权许可) <- 资源所有者
- © Authorization Grant(授权许可) -> 授权服务器 (Authorization Server)
- (D) Access Token(访问令牌) <- 授权服务器
- (E) Access Token(访问令牌) -> 资源服务器 (Resource Server)
- (F) Protected Resource(受保护资源) <- 资源服务器
Authorization Grant (授权许可)
- 定义:
- 表示资源所有者授权的凭据,客户端通过授权许可获取访问令牌 (Access Token)。
- 授权许可类型:
- Authorization Code (授权码)
- 授权码通过授权服务器获取。
- Implicit (隐式授权)
- 一种简化的授权码流程,适用于在浏览器中实现的客户端(例如 JavaScript)。
- 客户端直接被颁发访问令牌。
- Resource Owner Password Credentials (资源所有者密码凭据)
- 资源所有者的用户名和密码直接作为授权许可使用。
- 仅在资源所有者与客户端之间有高度信任时使用。
- Client Credentials (客户端凭据)
- 客户端凭据可用作授权许可。
- 通常用于客户端以自己的名义(即客户端也是资源所有者)操作的场景。
- Authorization Code (授权码)
- 注意: 不同类型的授权许可对应不同的授权协议流程,主要考察前两种。
Access Token (访问令牌)
- 定义:
- 用于访问受保护资源的凭据。
- 是分配给客户端的授权的字符串表示。
- 特点:
- 访问令牌提供抽象层,用单一令牌替换了不同的授权机制(例如用户名和密码)。
- 访问令牌可以有不同的格式、结构和使用方法。
- RFC6749 没有对访问令牌进行定义,其用法在 RFC6750 中规定。
Refresh Token (刷新令牌)
- 定义:
- 刷新令牌是一种用于获取访问令牌的凭据。
- 由授权服务器颁发给客户端,用于在当前访问令牌失效或过期时获取新的访问令牌。
- 仅供授权服务器使用。
OpenID
概述
- OpenID 是一个开放标准和去中心化的认证协议。
- OpenID 允许用户使用已有账户登录多个网站,而无需创建新的密码。
OpenID Connect (OIDC)
- OpenID Connect 1.0 是基于 OAuth 2.0 协议之上的一个简单身份层。
- 它使客户端能够基于由授权服务器执行的认证,验证终端用户的身份。
- OpenID Connect 将认证作为 OAuth 2.0 授权过程的扩展来实现:
- 在授权请求中包含
openid
范围值。 - 认证信息以 ID Token 的形式返回。
- 在授权请求中包含
OIDC 中的角色
- OpenID Providers (OPs):
- 支持 OAuth 2.0 的授权服务器,能够对终端用户进行认证,并向依赖方 (Relying Party) 提供与认证事件和终端用户相关的声明 (Claims)。
- Relying Parties (RPs):
- 支持 OAuth 2.0 的客户端应用,要求从 OpenID 提供方获取终端用户的认证和声明信息。
- 支持 OAuth 2.0 的客户端应用,要求从 OpenID 提供方获取终端用户的认证和声明信息。
OpenID Connect协议有三种类型
- 授权码鉴别
- 隐式鉴别
- 混合鉴别
- 三种协议流程的区别就是依赖方获得令牌的方式不同
- Authorization Code Flow (授权码模式)
- 特点:最安全,适合服务器端应用。
- 流程:通过授权码换取 ID Token 和 Access Token。
- 推荐场景:后台服务器和安全敏感场景。
- Implicit Flow (隐式模式)
- 特点:直接返回 ID Token 和 Access Token,省略授权码交换步骤。
- 缺点:安全性较低。
- 推荐场景:客户端浏览器直接与 IdP 通信。
- Hybrid Flow (混合模式)
- 特点:结合了授权码和隐式模式,允许部分令牌直接返回,同时获取授权码用于进一步交换。
- 推荐场景:需要更快响应时间的场景。
Authorization Code Flow (授权码模式) 流程
1. 准备授权请求(Prepare Authorization Request)
- Relying Party (RP) 构造一个授权请求,包含
client_id
、redirect_uri
、scope
等参数。 - 该请求通过用户代理(如浏览器)传递到 Authorization Server。
2. 授权请求(Authorization Request)
- 用户在 Authorization Server 上看到授权页面,登录并确认授权请求。
3. 验证用户身份(Authenticate End User)
- Authorization Server 验证终端用户的身份,例如通过用户名和密码或多因子验证。
4. 用户授权(Consent/Authorization)
- 用户同意授权请求(授权范围可能包括访问用户的电子邮件、姓名等)。
5. 重定向返回授权码(Redirect with Authorization Code)
- 用户授权后,Authorization Server 将用户重定向到 RP 提供的
redirect_uri
,并在 URI 参数中附带授权码(Authorization Code)。
6. 接收授权码(Receive Authorization Code)
- RP 接收从 Authorization Server 返回的授权码,用于后续请求令牌。
7. 令牌请求(Token Request)
- RP 使用授权码向 Token Endpoint 发起请求。
- 请求参数包括:
grant_type
(设置为authorization_code
)。code
(授权码)。redirect_uri
(需与初始授权请求中一致)。client_id
和client_secret
(用于 RP 身份验证)。
8. 返回 Access Token 和 ID Token
- Token Endpoint 验证授权码的有效性,并向 RP 返回以下令牌:
- Access Token: 用于访问用户受保护资源(如 UserInfo 端点)。
- ID Token: 用于验证终端用户身份。
9. 验证 ID Token(Validate ID Token and Get End User Subject Identifier)
- RP 验证 ID Token 的签名和声明字段:
- 验证
iss
(发布方)是否匹配授权服务器。 - 验证
aud
(受众)是否包含 RP 的client_id
。 - 验证
exp
(过期时间)确保令牌未过期。 - 验证
nonce
(防重放攻击)。
- 验证
10. 可选的 Access Token 使用(Optional Access Token Usage)
- RP 使用 Access Token 请求 UserInfo Endpoint 获取用户的详细信息。
11. 可选的 UserInfo 响应(Optional UserInfo Response)
- UserInfo Endpoint 返回用户信息,如姓名、电子邮件等。
关键技术要求
- ID Token 的签名与加密
- ID Tokens 必须使用 JWS(JSON Web Signature)进行签名。
- ID Token 可以同时签名和加密(使用 JWS 和 JWE)。
- 如果 ID Token 被加密,则必须先签名后加密。
- 安全通信
- 与 Authorization Server 的通信必须使用 TLS 加密。
- 与 Token Endpoint 的通信必须使用 TLS 加密,确保传输的授权码和令牌安全。
Implicit Flow(隐式模式)流程
流程步骤
1. 依赖方准备授权请求
依赖方(Relying Party,RP)准备一个授权请求,构造包含以下参数的 URL:
response_type
:设置为id_token
或id_token token
,表明隐式流程。client_id
:依赖方的标识符。redirect_uri
:授权完成后,授权服务器重定向的地址。scope
:包含openid
和其他所需权限(如profile
、email
)。state
:随机字符串,用于防止 CSRF 攻击。- (可选)
nonce
:随机字符串,用于防止重放攻击。
构造后的授权请求 URL 形如:
https://authorization-server.com/authorize?
response_type=id_token+token
&client_id=123456
&redirect_uri=https://client.example.org/cb
&scope=openid+profile+email
&state=xyz
&nonce=abc
2. 终端用户发送授权请求
用户通过浏览器向授权服务器发送授权请求,该请求通常被依赖方嵌入到重定向页面中。
3. 授权服务器鉴别终端用户
授权服务器对终端用户进行身份验证,常见的方式包括:
- 用户名和密码。
- 二维码扫描。
- 其他双因素认证方式。
如果用户已登录,则可以跳过身份验证步骤。
4. 终端用户同意授权
授权服务器向用户展示一个授权界面,明确显示依赖方请求的权限范围(Scope)。用户可以选择授权或拒绝授权。
5. 授权服务器重定向回依赖方
用户同意授权后,授权服务器将用户重定向到依赖方的 redirect_uri
,并在 URL 的哈希部分包含令牌信息。例如:
https://client.example.org/cb#
id_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
&access_token=SlAV32hkKG
&token_type=Bearer
&expires_in=3600
&state=xyz
如果用户拒绝授权,返回的 URL 会包含错误信息:
https://client.example.org/cb#
error=access_denied
&state=xyz
6. 依赖方接收 ID 令牌和访问令牌
依赖方从 URL 的哈希部分提取令牌:
- ID Token:用来验证终端用户的身份。
- Access Token:用于后续访问受保护资源。
7. 依赖方验证 ID 令牌
依赖方验证 ID 令牌的真实性,包括:
- 检查签名(验证其由授权服务器签发)。
- 检查
iss
(颁发者标识符)、aud
(接收方标识符,通常为依赖方的client_id
)是否匹配。 - 验证
exp
(过期时间)和iat
(签发时间)。 - 验证
nonce
,以确保令牌未被重放。
8. (可选)依赖方使用访问令牌访问受保护资源
依赖方可以使用 Access Token 向授权服务器的 UserInfo Endpoint 请求终端用户的详细信息(例如姓名、邮箱地址等)。
9. (可选)UserInfo Response
如果依赖方发起了 UserInfo 请求,授权服务器返回关于用户的声明(Claims),内容取决于 Scope 和 Claims 的定义。例如:
请求:
GET /userinfo HTTP/1.1
Host: server.example.com
Authorization: Bearer SlAV32hkKG
响应:
{
"sub": "248289761001",
"name": "Jane Doe",
"given_name": "Jane",
"family_name": "Doe",
"email": "janedoe@example.com",
"picture": "http://example.com/janedoe/me.jpg"
}
依赖方根据业务需求使用这些用户信息进行后续操作。
完整流程总结
- 依赖方准备授权请求:构造请求并重定向用户到授权服务器。
- 终端用户发送授权请求:通过浏览器将请求发送到授权服务器。
- 授权服务器鉴别终端用户:验证用户身份。
- 终端用户同意授权:用户授权依赖方访问其信息。
- 授权服务器重定向回依赖方:返回 ID Token 和 Access Token。
- 依赖方接收令牌:提取并处理返回的令牌。
- 依赖方验证 ID 令牌:确保 ID Token 的合法性和安全性。
- (可选)依赖方使用访问令牌访问资源:请求受保护的用户信息。
- (可选) UserInfo Response:授权服务器返回用户的详细信息。
关键特点
- 直接返回 Token
- 与 Authorization Code Flow(授权码模式) 不同,Implicit Flow 会直接返回 ID Token 和(或) Access Token,而不需要通过授权码换取。
- 省略服务器端交互
- 令牌直接通过浏览器传递给客户端,无需 RP 和授权服务器之间的服务器端通信。
- 适用场景
- 适合客户端直接与授权服务器交互的场景(如单页面应用 SPA 或浏览器应用)。
- 不适用于高安全性要求的场景。
隐式模式的主要安全挑战
- 令牌泄露
- 由于 Token 通过浏览器传递,可能被拦截。
- 必须使用 TLS 加密通信。
- Replay Attack(重放攻击)
- 通过
nonce
值和短时效的 Token 减少重放攻击的风险。
- 通过
- Token 放置问题
- 浏览器地址栏可能会暴露 Token,建议使用
fragment
部分避免 Token 被记录到服务器日志。
- 浏览器地址栏可能会暴露 Token,建议使用