目录
- 一、导语
- 二、初识OAuth2.0
- 三、OAuth2.0
- 四、OIDC1.0
- 五、OAuth2.0 & OIDC1.0授权模式选型建议
- 六、典型架构及示例
- 6.1 用户认证中心
- 6.2 客户端
- 6.3 应用网关
- 6.4 后端API服务
- 七、附录- OAuth & OIDC常用端点
一、导语
应用的使用离不开用户,所以用户认证与授权通常亦成为了应用架构中不可或缺的一部分。面对现如今多形态的应用架构体系(传统WEB、微服务、SPA、桌面端、移动端、IOT等),OAuth2.0 & OIDC 1.0提供了一套通用的用户认证与授权的最佳实践,本文首先通过集成微信登录来引入OAuth2.0相关概念,然后再对OAuth2.0和OIDC1.0各自进行了展开介绍,并给出了OAuth2.0 & OIDC 1.0授权模式的适用场景及选型建议,最后在文末给出了典型架构的集成示例。
二、初识OAuth2.0
随着应用架构的演进,在经历了传统的B/S session认证,市面上兴起了基于OAuth2的三方登录集成,如接入微信、Github登录等,也就是在这个时候OAuth 2.0(Open Authorization)逐渐进入了广大IT从业者的视线,而JWT(Json Web Token)作为OAuth2中的Token的实际载体因其安全性、无状态等特性也得到了广泛使用。现如今市面上越来越多的提供OAuth2.0 & OIDC1.0(OpenID Connect)接入的IDaaS(ID as a service)身份服务商(如Auth0、Authing、Azure ADFS等)的涌现,也说明了OAuth2.0 & OIDC 1.0的体系的逐步完善与流行。接下来让我们逐步揭开OAuth2.0和OIDC 1.0的神秘面纱。
以应用接入微信登录为例,如下为接入微信OAuth2.0登录的时序图:
在整个接入过程中,应用分为3种类型:
1)第三方应用
,即我们自己开发的应用(即对应OAuth2.0中的客户端Client
),需要引导用户
(即对应OAuth2.0中的资源拥有者Resource Owner
)跳转(浏览器端重定向、移动端调起App)到微信登录页面,在微信用户授权成功重定向回当前应用后,当前应用通过临时授权码code和客户端密钥信息(Client ID、Client Secret)获取访问令牌Access Token,然后携带Access Token需要获取微信的用户信息,并将微信用户信息其转换为当前应用的用户信息,此时还需要建立当前应用对应用户的登录态(如session,标识登录成功)。
2)微信用户认证服务
,即微信引导微信用户对第三方接入应用进行授权的服务(即对应OAuth2.0的授权服务器Authorization Server
),提供微信用户的认证和授权页面,如浏览器重定向到二维码扫码登录页面、移动端调起微信APP登录确认(即对应OAuth2.0的授权端点Authorization Endpoint),并在用户完成授权后携带临时的授权码Code重定向回第三方应用,并提供后续的令牌Token颁发服务(即对应OAuth2.0的令牌端点Token Endpoint,如通过code换取Access Token、Refresh Token,提供刷新Token服务)。
3)微信API服务
,即对接入的第三方应用提供查询微信用户详细信息的服务,且需要对第三方应用访问服务时携带的Access Token进行认证与鉴权(即对应OAuth2.0的资源服务器Resource Server
)。
如上描述的整个过程,即对应OAuth2.0中比较核心的2个授权模式:授权码(Authorization Code)模式和刷新令牌(Refresh Token)模式。
让我们思考下为什么微信OAuth2.0(也即OAuth2.0 授权码模式)接入要搞得这么复杂?
首先,第三方应用通过跳转(重定向、拉起微信APP)的方式,使得微信的用户在微信的应用范围内(微信Web域名下、微信APP内)完成认证和授权,则微信的用户及密码信息不会暴露给接入的第三方应用,提升了整个认证过程的安全性。再者,采用OAuth2.0协议后,第三方应用和微信的接入端点(授权端点、令牌端点)就此固定,二者只要保持此协议不变,不论后续微信的认证授权方式(无论是二维码、还是登录表单又或者提供了其他认证方式等)如何改变,对接入的第三方应用都是没有影响的,也就意味着微信端可以持续演进而又不影响已经接入的第三方应用。综上,虽然接入OAuth2.0带来一定复杂性,但是却给微信端带来了更高的安全性、灵活的扩展性,也给第三方应用带来了一劳永逸的认证接入体验,不受后续微信具体认证方式改变的影响,如此也便是OAuth2.0带来的优势。
接下来让我们站在不同角度来看上面提到的微信OAuth 2.0授权流程:
1)微信的角度,此时微信作为OAuth2.0中授权服务(Authorization Server)和资源服务(Resource Sever)的提供者,而我们接入的应用作为OAuth2.0中的客户端(Client)需要通过微信授权服务进行认证授权、通过微信资源服务获取用户信息。
2)身份云的角度,即IDaaS(ID as a service)身份服务商的角度,IDaaS服务商作为OAuth2.0中授权服务(Authorization Server)的提供者,并统一管理用户、组织、权限等用户相关信息,而我们接入的应用(Web、SPA、移动端APP等)作为OAuth2.0中的客户端(Client)需要通过IDaaS服务商的授权服务进行认证授权,而我们自己的API服务作为资源服务(Resource Server)的提供者,即我们的客户端在通过IDaaS进行认证后,携带IDaaS颁发的访问令牌Access Token访问我们自己的API服务,我们自己的API服务需要对访问令牌Access Token进行认证和鉴权(通过JWT签名公钥验证 或者 请求IDasS对令牌进行认证)。
3)自建统一用户认证中心的角度,在上面IDaaS的角度上更近一步,假如我们想要建设自己的用户认证中心,那我们的用户认证中心即作为OAuth2.0的授权服务(Authorization Server)的提供者,实现OAuth2.0的授权端点Authorization Endpoint、令牌端点Token Endpoint等,我们的应用都可以以客户端(Client)或者资源服务(Resource Server)的角色接入统一的用户认证中心。如此不难发现,OAuth2.0(结合后续提到的OIDC 1.0)同样适用于企业内部的统一用户认证中心的建设,同时亦可为其他第三方应用提供一致的用户认证接入体验。
三、OAuth2.0
OAuth 2.0(Open Authorization,开发授权) 是一个关于授权(Authorization)的开放行业标准,目前仅支持HTTP协议栈,适用于传统Web应用、SPA、移动端App、桌面应用及其他智能设备。OAuth2.0引入了授权服务器Authorization Server、客户端Client、资源拥有者Resource Owner、资源服务器Resource Server等概念,解耦并明确划分了各角色的职责。相较于传统认证模式,OAuth2.0通过向客户端Client颁发(在用户Resource Owner同意授权给客户端后)临时的访问令牌Access Token(JWT形式,包含访问的范围scope, 有效时长及其他自定义属性)的方式避免了用户的账号密码直接暴露给客户端,之后客户端Client使用访问令牌Access Token访问资源服务器Resource Server上被保护的资源,由资源服务器对携带访问令牌的请求进行认证与鉴权。借助JWT的优势,OAuth2.0可以更细粒度的控制单个访问令牌Access Token(对应单次授权而非用户全局设置)的访问范围(JWT scope)以及对单个访问令牌的吊销(对应OAuth2.0的Token Revocation Endpoint)。同时亦提供了令牌刷新模式(对应OAuth2.0的Refresh Token Endpoint),给用户带来体验更好的无感登录延续。
目前OAuth 2.0支持授权模式如下:
授权模式 | 说明 |
---|---|
授权码模式(Authorization Code) 通过code换取token | 较为常用,安全等级高,适用于存在Web后端的应用。 |
授权码+PKCE模式(Authorization Code With PKCE) 通过code+code_verifier换取token | 可适用于前端服务(SPA)、原生应用(桌面、移动端)。 |
客户端凭证模式(Client Credentials) 通过Cient凭证(ClientId和Secret)换取token | 适用于服务器间(M2M)通信。 |
刷新令牌模式(Refresh Token) 通过refresh_token换取新token | 根据之前授权通过时颁发的refresh_token获取新的access_token,避免用户多次重复登录(无感登录),提升用户体验。 |
设备码模式(Device Code) deviceCode+UserCode+VerficationUri 引导用户通过其他设备(如手机)进行认证授权 | 适用于可联网的无浏览器或输入受限的设备授权,例如智能电视、电子相册、打印机等。 |
隐式模式(Implicit) 直接返回token | 不推荐, 作为授权码模式的备用选项。 |
密码模式(Password) 直接通过用户名密码换取token | 不推荐, 最不安全,客户端需要知道用户账号, 且客户端与认证方式强绑定,后续认证方式修改客户端也需要一起修改。 |
目前OAuth 2.0支持授权模式如下:
关于 授权码模式(Authorization Code) 和 刷新令牌模式(Refresh Token) 可以参见上文提到的微信OAuth2.0认证授权接入,而表中提到的隐式模式(Implict)省略了授权码模式中的授权码Code的颁发,而是直接将令牌Token返回给客户端,此种模式将令牌Token直接暴露到浏览器端,增加了令牌被泄露的风险,因此OAuth社区已不再推荐此模式,目前仅在无法使用授权码模式的情况下作为备选项。
而之前提到的授权码模式需要客户端可以安全的存储客户端密钥,而对于现如今的SPA、移动端等客户端,由于其直接暴露在客户端的运行环境(区别于后端服务器应用,用户无法直接访问服务器),用户通过特殊手段可以查看其代码,因此存在暴露客户端密钥的风险。鉴于此OAuth2.0提供了授权码+PKCE模式(Authorization Code With PKCE),该模式在授权码模式的基础上使用**PKCE(Proof Key for Code Exchange)**的密码学手段,确保恶意第三方即使截获Authorization Code,也无法向认证服务器交换Access Token,同时不需要在客户端存储密钥Client Secret,避免Client Secret被泄露,具体授权码+PKCE模式的时序图如下:
客户端凭证模式(Client Credentials) 适用于服务器间(M2M)通信,即不涉及具体的用户操作,为每个服务器预先颁发一套客户端凭证信息(Client ID、Client Secret),然后服务器直接调用授权服务器,通过客户端凭证信息换取访问令牌Token,之后携带访问令牌Access Token与其他资源服务器(Resource Server)进行通信,具体客户端凭证模式的时序图如下:
密码模式(Password) 是最容易实现的一种模式,但同时也是最不推荐的模式。即客户端拿到用户的账号密码后,直接调用授权服务(Authorization Server)的令牌端点(Token Endpoint)获取访问令牌Access Token,密码模式的具体时序图如下:
试想微信的账号密码暴露给接入的客户端Client(比如新开发的App接入微信登录),那么Client端就可以拿着用户的微信账号为所欲为,这显然是最不安全的,微信也绝不可能同意,即便是我们自建的认证中心,接入的Client端也都是我们自己公司的应用,接入的Client都能拿到用户账号密码,显然也增加了用户账号密码泄露的风险,显然也是不可取的,关于用户的账密码,还是越少人(越少Client端应用)知道越好。还有一点就是使用密码模式(username、password)方式进行登录,客户端会与认证方式进行绑定,例如今天通过用户名、密码登录,明天想通过手机号、验证码登录,后天添加验证码…,那么客户端都得跟着修改,仅使用username、password两个参数是远远不够的,所以就进入了用户认证逻辑一修改,所有客户端都得跟着修改的情况,而使用授权码这种模式,客户端和认证中心的协议是固定的,认证逻辑的修改仅限制在认证中心,并不会影响客户端。如此也就是不推荐密码模式的原因。
设备码模式(Device Code) 适用于可联网的无浏览器或输入受限的设备授权,例如智能电视、电子相册、打印机等。可以参考智能电视上的应用登录,此时智能电视即为设备,而安装在智能电视上的应用即为客户端Client,电视上的应用首先向授权服务器发起获取设备码请求,然后电视上的应用与后端的授权服务器根据返回的设备码(Device Code)建立长轮询,同时引导用户访问Verification Url并输入正确的User Code,授权服务端对User Code确认无误后,会再引导到用户进行登录与授权(整个引导过程可以简化为用户体验更好的扫描二维码登录),当授权服务端检测到用户已对当前电视设备上的应用进行认证与授权后会第一时间通知设备端的应用并返回访问令牌Access Token,之后电视设备上的应用即可通过访问令牌Access Token与其他资源服务器(Resource Server)进行通信,具体设备码模式的时序图如下:
除了之前提到的OAuth2.0,目前新的OAuth2.1草案也已经发布,相较于OAuth2.0其主要变化如下:
- 仅保留授权码(Authorization Code),客户端凭证(Client Credentials),刷新令牌(Refresh Token),设备码(Device Code)模式。
- 移除隐式模式(Implicit)和密码模式(Password)。
- 授权码模式必须使用PKCE。
- Bearer Token不可使用query参数形式
- 刷新令牌模式(Refresh Token for Public Client)更加严格,即对于无法提供Client Secret的客户端进行合理的限制(sender-contrained),又或者Refresh Token仅能使用一次(one-time),每次刷新后作废旧的Refresh Token并同步颁发新的Refresh Token。
四、OIDC1.0
OIDC1.0(OpenID Connect) 在OAuth2.0上构建了一个身份层(Identity, Authentication),是一个基于OAuth2.0协议的身份认证标准协议(OAuth2.0的超集)。OAuth2.0更关注授权,OIDC1.0使用OAuth2的授权服务器来为第三方客户端提供用户的身份认证,并把对应的身份认证信息ID Token传递给客户端,且提供获取用户信息的接口(UserInfo Endpoint),适用于各种类型的客户端(比如服务端Server应用,移动端APP,JS应用(SPA)等),且完全兼容OAuth2.0,也就是说你搭建了一个OIDC1.0的认证服务后,也可以当作一个OAuth2.0的授权服务来用。现阶段实现用户认证及鉴权(先鉴权用户再返回资源)以及单点登录SSO、单点登出SLO,优先建议使用 OIDC1.0协议。
OIDC1.0协议中的术语与OAuth2.0内容基本一致,但是叫法却有些区别,二者对比如下表:
OIDC1.0 | OAuth2.0 | 说明 |
---|---|---|
EU End User | Resource Owner | 拥有资源的用户 |
RP Relying Party | Client Third-party application | 来代指OAuth2中的受信任的客户端(Web应用、SPA、移动端应用…),即接入认证中心(OP、Authorization Server)登录跳转且并且获取Token(IdToken、AccessToken),可通过IdToken获取用户身份信息, 然后携带AccessToken访问资源(Resource Server、Userinfo Endpoint) |
OP OpenID Provider | Auhtorization Server | 为用户(EU、Resource Owner)提供认证的服务(如微信授权平台、Github授权平台、自建用户中心等),用来为应用客户端(RP、Client)提供用户(EU、Resource Owner)的身份认证信息。 |
Resource Server | Resource Server | 资源服务器,即提供资源API且需要对(受保护的)资源访问进行鉴权的服务,Cilent端携带AccessToken访问ResourceServer,然后由Resource Server对此AccessToken进行鉴权。 |
Endpoint | Endpoint | 端点,即提供的API接口 |
ID Token | 无 | 身份令牌(JWT),用于认证,标识用户身份已经认证,可用于获取用户身份信息(如用户名、头像等),同时客户端需对获取到的ID Token进行签名验证、属性验证(aud、azp、nonce等)。 |
Access Token | Access Token | 访问令牌(JWT),用于鉴权,适用于API的访问鉴权。 |
User Agent | User Agent | 应用执行端,如浏览器,手机端,即RP的执行端。 |
OIDC1.0定义了实现单点登录SSO、单点登出SLO的扩展协议,相关协议如下:
OIDC1.0补充协议 | 说明 |
---|---|
OpenID Connect Core 1.0 - UserInfo Endpoint | RP端向OP发出查询用户详细信息的请求。 |
OpenID Connect RP-Initiated Logout 1.0 | RP端向OP发出的初始登出请求(适用于单点登出SLO,end_session_endpoint),OP首先清除OP端的session,然后向当前session下的其他已登录的RP触发Front-Channel或者Back-Channel登出请求,最终可通过post_logout_redirect_uri 重定向会当前RP。 |
OpenID Connect Front-Channel Logout 1.0 | 返回OP前端登出页面,页面通过嵌入iframe(src=frontchannel_logout_uri),同时触发当前OP Session对应的多个Client的登出接口。 |
OpenID Connect Back-Channel Logout 1.0 | OP直接向当前OP Session对应的多个Client后端服务(不依赖User Agent,如不依赖浏览器)发送登出请求backchannel_logout_uri,且适用于User Agent被关闭的时候也可以退出登录。 |
OpenID Connect Session Management 1.0 | RP端通过check_session_iframe监听当前UserAgent中用户的登录状态,收到登录状态改变通知后RP应该清除自己的Session信息、页面跳转等。 |
五、OAuth2.0 & OIDC1.0授权模式选型建议
关于授权模式的选择可以参见下图(图片截取自国内身份云厂商Authing - 选择OIDC授权模式):
总结上图,关于OAuth2.0 & OIDC1.0授权模式的最佳选型建议如下:
应用类型(即Client) | 选型建议 |
---|---|
WEB应用(即存在Web后端服务) 适用于获取第三方资源、集成第三方登录(如微信登录) | 授权码模式 接入OAuth后携带code回调到Web后端, 由后端获取AccessToken, 在后端携带AccessToken请求资源, 可使用session存储Token和User信息, 即使用session作为当前Web应用的身份验证机制 |
服务器间通信 无终端用户 | Client Credentials 模式 |
SPA 如Vue、React等单页应用(前后端分离), 有专门的后端资源服务层(Resource Server)提供API服务 | PKCE + 授权码模式 即由前端接入认证,而后端仅接入鉴权 注:如采用Nodej.js运行时环境并提供安全的后端存储,则可直接使用授权码模式。 |
原生应用Native(移动端应用、桌面应用) 如Android、Ios(前后端分离), 有专门的后端服务层(Resource Server)提供API服务 | PKCE + 授权码模式 即由前端接入认证,而后端仅接入鉴权 |
六、典型架构及示例
接下来我们以如下比较典型的架构(前后端分离+微服务+应用网关)为例,具体讲解如何结合Spring生态(Spring Cloud Gateway、Spring Security OAuth2)实现一套基于OAuth2.0 & OIDC1.0(授权码+PKCE)的统一用户认证及鉴权示例,整体架构如下图:
各应用类型说明如下表:
应用类型 | OAuth2.0 & OIDC1.0角色 | 开发框架 |
---|---|---|
用户认证中心User Auth Center 为用户(EU、Resource Owner)提供认证的服务 | Authorization Server & OP | Java 8+ spring-authorization-server MySql |
前端SPA客户端 向用户认证中心请求授权并通过应用网关访问资源API | Client & RP | Vue / React /… Node.js openid-cilent (示例基于spring-boot-starter-oauth2-client) |
应用网关API GW 负责请求转发及请求鉴权等 | Resource Server | Java 8+ spring-cloud-starter-gateway spring-boot-starter-oauth2-resource-server |
后端服务WEB/RPC 提供API服务 | 无 | Java 8+ spring-boot-starter-web WebClient(可根据需要调整对应RPC框架 ) |
各应用间交互的时序图如下:
接下来对各应用的具体实现依次说明。
6.1 用户认证中心
用户认证中心可基于Spring社区开源的OAuth2授权服务器实现:
https://github.com/spring-projects/spring-authorization-server
spring-authorization-server构建于Spring Security之上,所以可以通过简单的实现UserDetailsService来完成用户信息的检索,且关于授权信息的后端存储支持JDBC实现(支持自定义实现),与Spring框架集成方便,支持主流的OAuth2.0 & OIDC1.0授权模式,如授权码(Authorization Code)、授权码+PKCE(本示例基于此模式)、客户端凭证(Client Credentials)、刷新令牌(Refresh Token)等。在集成启动认证服务器后,还需要注册对应的客户端信息(即对应本示例的客户端定义),注册代码如下:
在认证服务集成启动后,客户端即可通过认证服务提供的自动发现端点(/.well-known/openid-configuration),获取OAuth2.0 & OIDC1.0的端点、授权类型、公钥等相关信息,具体返回信息如下:
在OAuth2.0协议中关于用户具体的 登录方式(账号密码、手机号、集成第三方等) 和 授权方式(授权页面,如点击按钮确认等) 并没有给出定义,开发者可以根据需要灵活扩展,此处的变动并不会影响整个OAuth2.0授权流程,对接入的客户端也没有影响。本例采用spring-authorization-server实现授权服务器,其底层默认使用Spring Security的FormLogin模块,所以在用户进行认证时,其默认的登录页面如下:
6.2 客户端
客户端采用SPA实现可参见:https://github.com/panva/node-openid-client,本作者非专业前端开发,所以以后端集成为例,但二者集成原理类似,同样具有借鉴作用。作为客户端,其主要的工作包括:
1)引导用户跳转(附加PKCE挑战码coder_challenge)到统一用户认证授权页面(即对应OAuth2.0授权端点Authorization Endpoint)。
2)处理授权码Authroization Code回调请求,携带授权码(附加PKCE验证码coder_verifier)调用统一用户认证服务(即对应OAuth2.0的令牌端点Token Endpoint)换取访问令牌Access Token、身份令牌ID Token和刷新令牌Refresh Token。
3)验证身份令牌ID Token(签名验证、属性验证aud、azp、nonce等)
4)安全地存储令牌(加密存储 或session存储)。
5)携带访问令牌Access Token获取并存储用户详细信息(即对应OIDC1.0 UserInfo Endpoint)
6)携带访问令牌Access Token访问API服务(即访问应用网关后再由网关进行转发)
7)待访问令牌即将过期时自动刷新令牌
可以发现,客户端的工作内容还是比较多的,但是借助相关的OIDC开发框架(如SPA端的openid-connect,Java端的spring-boot-starter-oauth2-client),集成还是很方便的。有了这些框架帮助开发者把核心流程、API等固定下来(上面提到的1~5,7步都由框架完成),开发要做的就只剩如下几块:
1)配置客户端注册信息,需要与之前在用户认证中心Authorization Server中的注册信息相对应,示例配置如下:
2)获取发起请求的用户信息(例如需根据用户身份查询数据等),在Spring Security中可通过SecurityContextHolder.getContext().getAuthentication()获取,又或者直接通过参数注入进行获取,示例如下图:
3)访问资源服务时携带令牌(Bearer Token),例如使用WebClient进行Http调用的集成示例代码如下:
6.3 应用网关
由之前的客户端Client对Resource Server(也即此应用网关)发起调用,Resource Server提取请求头中的Authorization: Bearer AccessToken 中的AccessToken,此处的AccessToken即对应OAuth2.0的Access Token,Resource Server端提供2种对此令牌的鉴权方式:
1)方式1 - JWT:Resource Server端通过public JWK(JWT签名公钥或其发现端点)对令牌中的签名进行验证,配置示例如下:
2)方式2- Opaque Token:Resource Server端调用授权服务器(即之前的用户认证中心)端的令牌验证端点(introspection-uri)对令牌进行验证,配置示例如下:
关于以上2种方式,推荐方式1 -JWT,可以减少一次Resource Server到授权服务端的HTTP调用,性能更好。若应用场景中对令牌时效及安全性有强制要求,可配合使用方式2 - Opaque Token和OAuth2.0的吊销令牌端点(Token Revocation Endpoint),即完全由授权服务端控制令牌的有效性,但性能相应也会有所降低。
在以上2种鉴权方式的基础上,亦可添加额外的自定义权限验证,示例代码如下:
6.4 后端API服务
由于使用了SCG应用网关,将用户鉴权的操作前置到网关层,所以后端的服务实现仅需关注核心业务逻辑即可。如果后端API服务有获取用户身份的需要(例如需根据用户身份查询数据、确定操作人等),可参见如下几种实现方式:
-
1)SCG应用网关将客户端请求中携带的请求头Authorization: Bearer AccessToken透传到后端服务,后端服务通过解析此Access Token(无需JWT签名公钥)中的相关属性便可获取对应的用户信息(如JWT sub)。
-
2)可在SCG应用网关处对AccessToken属性(如JWT sub)进行解析,生成用户信息后再通过指定请求头透传到后端服务,后端服务可直接通过该请求头获取用户信息。
-
3)由客户端提供用户信息(解析ID Token或者UserInfo)作为参数或者请求头,然后由网关透传到后端服务,后端服务可直接解析对应的用户信息。
关于后端服务间的相互调用为集群内的服务调用,可无需鉴权,仅通过应用网关进入(客户端调用)的请求需要鉴权。若对集群内的服务间调用有安全层面的限制,建议通过Service Mesh层面(如使用Istio的AuthorizationPolicy)进行控制,避免服务过于臃肿。
七、附录- OAuth & OIDC常用端点
OIDC和OAuth的常用端点(Endpoint,即提供的API接口)
endpoint | 提供方 | 调用方 | 认证 | 格式 | desc |
---|---|---|---|---|---|
authoriztion_endpoint | OP | RP | 无 | Code Flow模式: GET authorization_endpoint ?response_type=code &redirect_uri={redirect_uri} &client_id={client_id} &state={random_str} &nonce={another_random_str} &scope=openid profile email PKCE + Code Flow模式 (额外添加code_challenge参数) GET authorization_endpoint ?response_type=code &redirect_uri={redirect_uri} &client_id={client_id} &state={random_str} &nonce={another_random_str} &scope=openid profile email &code_challenge_method=S256 &code_challenge={code_challenge} | 进入OP登录授权界面 |
redirect_uri | RP | OP | 无 | GET redirect_uri ?code={code} &state={random_str} | 在OP登录成功后,将code回调给RP |
token_endpoint | OP | RP | client_secret_post client_secret_basic | Code Flow模式: POST token_endpoint ?grant_type=authorization_code &code={code} &redirect_uri={redirect_uri} &client_id={client_id} &client_secret={client_secret} PKCE + Code Flow模式 (删除client_secret参数后 额外添加code_verfier参数) POST token_endpoint ?grant_type=authorization_code &code={code} &redirect_uri={redirect_uri} &client_id={client_id} &code_verifier={code_verifier} 客户端凭证模式: POST token_endpoint ?grant_type=client_credentials &client_id={client_id} &client_secret={client_secret} &scope=user roles(空格分隔的scope列表) Refresh Token模式: POST token_endpoint ?grant_type=refresh_token &client_id={client_id} &client_secret={client_secret} &refresh_token={refresh_token} 注:在PKCE模式下、客户端凭证模式下不支持刷新token流程 | 通过code获取access_token、id_token, 根据refresh_token获取新的access_token |
userinfo_endpoint | OP | RP | Bearer {access_token} | GET userinfo_endpoint | 根据acces_token获取用户信息 |
introspection_endpoint | OP | Resource Server | client_secret_post client_secret_basic | POST introspection_endpoint ?token={your_token} | 用于验证access_token是否有效, 通过返回结果中的active进行标识 |
revocation_endpoint | OP | RP | client_secret_post client_secret_basic | POST revocation_endpoint ?token={your_token} &token_type_hint={} &token_type_hint=access_token | 撤销token、access_token, 若撤销refresh_token,则此refresh_token关联的access_token也会被撤销 |
end_session_endpoint | OP | RP | 无 | GET end_session_point ?id_token_hint={id_token_issued_to_client} &post_logout_redirect_uri={post_logout_redirect_uri} &state={random_str} | 结束浏览器中OP的session会话, 并触发后续的多RP的Front-Channel或Back-Channel登出, 最后可配合post_logout_redirect_uri 重定向回RP页面 |
post_logout_redirect_uri | RP | OP | 无 | GET post_logout_redirect_uri | OP登出成功后会重定向回RP页面, 或对应于RP登录界面、登出状态展示页面等 |
check_session_iframe | OP | RP | 无 | RP iframe.src=check_session_iframe | Session Management,检查当前RP的登录状态 |
frontchannel_logout_uri | RP | OP iframe | 无 | GET fontchannel_logout_uri ?iss={issureId} &sid={idToken.sid} | RP前端实现的登出处理页面, 由OP Front-Channel模式下返回的Html iframe调用 |
backchannel_logout_uri | RP | OP | 无 | POST backchannel_logout_uri ?logout_token={logout_token like idToken} | RP后端实现的后端登出接口, RP后端需验证logout_token并根据logout_token找出并清除后端的对应的session信息 |