认识
一、认识
在 Web
应用中实现跨不同顶级域的 SSO
(单点登录) 方案,通常会面临浏览器同源策略(Same-Origin Policy
)的限制。在同顶级域下,通过设置 Cookie
的 domain
属性可以轻松实现跨子域的认证。然而,在不同顶级域(例如 example.com
和 example.org
)下,由于浏览器的安全策略,不同的顶级域不能直接共享 Cookie
, 直接通过 Cookie
来实现跨域认证变得困难。
OIDC
是建立在 OAuth 2.0
协议之上的,但与 OAuth 2.0
主要聚焦于授权不同,OIDC
关注的是用户身份认证。OIDC
允许客户端通过 ID Token
来验证用户的身份,同时还可以使用 Access Token
来访问授权的资源。
-
OAuth 2.0
: 是一个授权框架,允许第三方应用在不暴露用户凭证的情况下,访问用户在某些资源服务器上的数据。 -
OpenID Connect (OIDC)
: 基于OAuth 2.0
的身份验证协议,OIDC
不仅关注授权,还包括认证功能,允许客户端应用确认用户的身份。
二、工作流
基于 OIDC SSO
架构为:
-
身份提供者 (
IdP
Identity Provider
): 比如idp.example.com
,负责用户的身份认证、颁发令牌Access Token
、Refresh Token
、ID Token
, 提供统一认证服务, 并维护全局会话, 并将Token
信息写入到IdP
域的Cookie
中 -
服务提供者 (
SP
Service Provider
):app.example.com
、portal.example.org
、ccc.example.xyz
等多个Web
应用, 受信任的第三方应用, 依赖于IdP
来进行身份验证。用户通过IdP
的令牌验证身份后,SP
创建局部会话, 并将Token
信息写入到SP
域的Cookie
中
基于 OIDC SSO
工作流为:
1. 用户登录认证: 用户访问 SP1
如 app.example.com
时,SP1
会检查是否已有有效的 Access Token
存储在 Cookie
中。如果没有有效的 Access Token
,SP1
会将用户重定向到 IdP
进行认证。SP1
重定向到 IdP
授权端点时, 附带必要的查询参数,如 client_id
、redirect_uri
、scope
(如 openid
profile
email
)、response_type
(如 code
)等。用户在 IdP
提供的登录页面上输入用户名和密码(或通过其他身份认证方式),IdP
会验证用户身份并生成 授权码(Authorization Code
)。用户认证成功后, IdP
会创建全局会话, 并将 Token
信息写入到 IdP
域的 Cookie
中。然后 IdP
会将用户重定向回 SP1
的 redirect_uri
,并在 URL
中附带一个 授权码(code
)。SP1
将会使用授权码通过 POST
请求向 IdP
请求 Access Token
和 ID Token
。 SP1
验证 ID Token
有效性通过令牌验证身份后,创建局部会话, 并将 Token
信息写入到 SP
域的 Cookie
中, 最后返回 SP1
页面。
-
IdP
使用Cookie
标记全局会话: 并将对应Token
存储到IdP
域的Cookie
中,并设置HttpOnly
、Secure
、SameSite=None
-
SP
使用ID Token
验证并管理用户的局部会话: 并将对应Token
存储到IdP
域的Cookie
中,并设置HttpOnly
、Secure
、SameSite=None
-
ID Token
: 在OIDC
中,ID Token
是一个JWT
,它包含了用户的身份信息。ID Token
是OIDC
的核心组件,用于提供关于用户身份的声明。在我们的IdP
实现中,生成ID Token
是必要的,我们可以通过在JWT
中添加一些关于用户的基本信息(如sub
、name
、email
等)来构建ID Token
。ID Token
由身份提供者(Id
P)签发,SP
可以使用这个Token
来识别用户,并在后续的API
调用中进行认证。 -
Access Token
:Access Token
是一个JWT
或其他格式的Token
,它用于代表授权的用户访问受保护的资源。Access Token
通常较短期有效,且其作用范围通常局限于授权的服务端API
。 -
Refresh Token
:Refresh Token
是一个长期有效的Token
,用于获取新的Access Token
,无需用户重新认证。通过刷新Access Token
,可以维持用户会话,避免频繁要求用户登录。 -
授权码交换: 授权码 (
Authorization Code
) 是用来获取Access Token
和ID Token
、Refresh Token
的。首先,用户将被重定向到IdP
进行认证,然后IdP
会返回一个授权码给SP
。SP
拿到授权码后,再通过后台向IdP
申请Access Token
和ID Token
、Refresh Token
,并通过这些Token
来访问用户的身份信息。 -
Session
管理:OIDC
中的会话管理是另一个重要的部分,IdP
需要确保用户的会话在有效期内。通常会话信息需要存储在Redis
或数据库中,确保在不同应用之间能共享会话信息。
2. 用户后续请求验证: SP1
在用户发起 API
请求时, 会自动携带局部 Access Token
。当 Access Token
过期时,SP1
可以通过存储的 Refresh Token
向 IdP
请求新的 Access Token
和 ID Token
。这一步骤对用户来说是无感知的,无需重新登录。
3. 跨服务提供者的认证: 用户访问 SP2(portal.example.org)
或 SP3(ccc.example.xyz)
时,SP2
或 SP3
会检查用户是否已经认证。未认证时,会将用户重定向到 IdP
进行认证。IdP
会检查用户的全局会话,确认用户已经认证, 如果用户会话仍然有效, 会直接生成新的授权码, 省略了用户登录的流程。然后 SP2
、SP3
获取授权码之后, 通过授权码获取相关 Token
信息, 验证 ID Token
, 创建局部会话, 并将 Token
信息写入到 SP
域的 Cookie
中, 最后返回 SP2
、SP3
页面。
用户在 SP1
和 SP2
之间的认证是通过 IdP
中的全局会话来完成的。SP1
和 SP2
都依赖于 IdP
维护的用户认证信息、全局会话,但它们分别维护各自的局部会话。这种跨域、跨应用的认证机制即实现了 SSO(Single Sign-On)
,用户只需要在第一次登录时输入用户名和密码,后续的访问请求都会自动完成认证,无需再次登录。
用户登录成功之后,会与 IdP
(Identity Provider
,身份提供者) 及各个 SP
(Service Provider
,服务提供者) 建立会话,用户与 IdP
(Identity Provider
,身份提供者) 建立的会话称为全局会话,用户与各个 SP
(Service Provider
,服务提供者) 建立的会话称为局部会话,局部会话建立之后,用户访问子系统受保护资源将不再通过 IdP
(Identity Provider
,身份提供者),全局会话与局部会话有如下约束关系
-
局部会话存在,全局会话一定存在
-
全局会话存在,局部会话不一定存在
-
全局会话销毁,局部会话必须销毁