OAuth 2 授权码许可工作流程分析

一、授权码许可工作流程

授权码许可类型将所有不同的 OAuth 参与方完全隔离,是整个协议中最复杂、安全性最高的一种许可类型,其他许可类型无外乎是针对特定场景的优化。

OAuth 2.0 的核心工作流程就是颁发令牌与使用令牌,最常用的授权码许可的工作流程如下,Authorization Code Flow:

scss 复制代码
     +----------+
     | Resource |
     |   Owner  |
     |          |
     +----------+
          ^
          |
         (B)
     +----|-----+          Client Identifier      +---------------+
     |         -+----(A)-- & Redirection URI ---->|               |
     |  User-   |                                 | Authorization |
     |  Agent  -+----(B)-- User authenticates --->|     Server    |
     |          |                                 |               |
     |         -+----(C)-- Authorization Code ---<|               |
     +-|----|---+                                 +---------------+
       |    |                                         ^      v
      (A)  (C)                                        |      |
       |    |                                         |      |
       ^    v                                         |      |
     +---------+                                      |      |
     |         |>---(D)-- Authorization Code ---------'      |
     |  Client |          & Redirection URI                  |
     |         |                                             |
     |         |<---(E)----- Access Token -------------------'
     +---------+       (w/ Optional Refresh Token)

1、资源拥有者委托用户代理,携带重定向地址、客户端标识等信息,向授权服务发起授权申请 2、授权服务在经过请求用户、客户端标识等验证后,携带授权码重定向到指定地址 3、客户端接收到授权码后向授权服务换取令牌,授权码使用一次立即失效 4、拿到令牌后,客户端就可以向受保护资源发起资源申请,受保护服务校验令牌通过后开放资源访问权限

二、主要角色功能分析

换成时序图,可以更直观了解授权码许可的工作流程。下面我们逐一分析各角色的主要功能。

1、客户端

客户端是 OAuth 生态中使用最广泛的角色,其复杂度也得到了很大简化,除却注册申请部分,甚至只需要维护一个 bearer 令牌就可以访问受保护资源。

(1)注册客户端

向授权服务器注册客户端,分为静态注册与动态注册。

授权服务器分配 client_id,client_secret,用于客户端与授权服务器交互做身份认证,传输 client_secret 一般使用 HTTP 基本认证方式。

客户端注册时还要提供授权码接收端点以及 redirect_uri,还有 scope 等字段。

客户端还要能发现服务器,并将授权端点(比如:http://127.0.0.1:9000/oauth2/authorize)、令牌端点(比如:http://127.0.0.1:9000/oauth2/token)保存下来。

(2)申请授权

首先客户端会向授权服务的授权端点发起授权申请,携带注册客户端包含的一系列参数。由于 OAuth 2 对于资源拥有者授权过程的设计是在前端信道重定向完成的,因此一旦客户端发起授权申请后授权流程就不再受控制了,直到接收到来自授权服务的回调请求。

接着是一个处理授权相应的过程,在提供给授权服务重定向 URI 的端点上接收到授权码和 state 参数,state 需要和申请时的相同参数做校验,不一致就要终止授权流程。

校验通过后,就可以携带授权码访问授权服务的令牌端点换取访问令牌了。

(3)使用令牌

OAuth 2 推荐使用 HTTP Authorization 请求头作为令牌访问受保护资源的方式,报文如下:

http 复制代码
GET /resource HTTP/1.1
Host: 127.0.0.1:9001
Accept: application/json
Connection: keep-alive
Authorization: Bearer 987tghjkiu6trfghjuytrghj

这种令牌称之为 bearer 令牌,OAuth 推荐三种发送 bearer 令牌的方式:HTTP Authorization 请求头,表单参数和 URL 编码的查询参数。受保护资源不对 bearer 令牌持有者做区分,只要持有即可访问受保护资源。

(4)刷新令牌

申请授权时获得的访问令牌是有过期时间的,一旦过期而资源拥有者又不在场的情况下,刷新令牌就派上用场了。

刷新令牌是与访问令牌一同返回给客户端的,在访问令牌失效后,可以使用刷新令牌重新申请访问令牌,并继续使用访问令牌请求受保护资源。刷新令牌的过期时间是远长于访问令牌的。

最后两个令牌都失效了,就又需要资源拥有者出面给与客户端授权了。

2、受保护资源

受保护资源经过 OAuth 设定增加了一层访问控制,最终都会以 API 的形式提供资源服务给客户端。简单地,可以与授权服务部署在一起。

(1)解析令牌

资源服务整个 OAuth 2 协议中只提供一个面向客户端的资源访问端点,解析客户端的令牌,并与存储中令牌做比对校验。

在一些设计中经常会看到授权服务器与资源服务器共享数据库的情况,就是为了方便令牌的颁发、存储与验证。令牌的管理本身也不在 OAuth 2 协议内,常规做法是存储令牌的哈希值。除了共享数据库,令牌校验还可以通过令牌内省的方式完成。

(2)提供有差别的 API

令牌验证通过后,就要根据访问权限提供资源了,也就是 API。如何设计资源权限又是另一个话题,一般来说,不同权限对应不同操作,不同权限对应不同数据结果,不同用户对应不同数据结果。

对于客户端而言,是不清楚资源拥有者的个人信息的,受保护资源都是以 API 形式提供的,可以起到保护用户隐私的作用。

3、授权服务

(1)管理客户端

处理客户端注册,分配 client_id 和 client_secret 并通知服务器、授权端点和令牌端点的地址,并管理已注册的客户端。设置黑白名单,监控异常客户端等。

(2)处理授权申请

授权服务提供授权端点,以及客户端授权页面。这里需要借助 OIDC 等协议验证资源拥有者的真实性,身份认证不在 OAuth 2 协议范围内却是关键环节。

授权通过后,授权流程又交换给了客户端,等待客户端换取访问令牌。

(3)颁发令牌

授权服务提供令牌端点。接收换取令牌的请求,优先从 Authorization 请求头中解析客户端标识和密钥,也就是前面客户端申请授权提到的使用 client_id 和 client_secret 经过 URL 编码写入的 Basic Auth 值。同时校验的还有授权码、授权范围等。

接着处理(授权码)授权许可请求,根据 code 值换取令牌。code 值一经使用即废弃,令牌内容可以在授权服务与受保护资源间协商,对客户端是不可见的。

(4)刷新令牌

令牌颁发后访问令牌只在受保护资源使用,刷新令牌在授权服务使用。OAuth 2 的权限范围是用空格分隔的字符串,一般刷新令牌的权限范围不能超过访问令牌。

虽然换取访问令牌已经做了客户端认证,但是为了防止客户端盗用,申请刷新令牌也要做身份认证。验证不通过刷新令牌也要丢弃。

至于刷新令牌也可以有很强的扩展空间,比如令牌丢弃、令牌撤回、刷新令牌过期时间等。

三、Q & A

Q1:不要授权码,直接重定向返回访问令牌是否可行呢?

OAuth 2 授权码许可的本质是授权代理,也就是将受保护资源的部分权限委托给客户端,实际受保护资源还是归属于资源拥有者的。

客户端作为授权代理,使用授权码作为代理凭证,通过授权码建立起身份凭证与授权许可的连接,也保护了资源拥有者的身份凭证不被泄露。从而实现一种三方制约------资源拥有者可以放心授权没被滥用、密码等凭据最小授权,受保护资源也可放心客户端是合法请求没有拖库等危险动作、对客户端请求有效监管、控制资源开放能力,客户端也完成了对资源拥有者的合法代理、完成拥有者的诉求、成就代理商生态

如果直接重定向返回访问令牌,首先在前端信道上暴露令牌是不安全的,容易被窃取;再者,授权服务失去了与客户端建立连接,不能确保使用令牌的客户端的合法性。通过授权码,客户端通过后端信道主动向授权服务换取访问令牌,减少了令牌泄露与客户端请求伪造的风险。

Q2:授权码许可过程中,两次重定向的作用?

首先,OAuth 2 基于 HTTP 设计,重定向是前端之间的行为,后台驱动前台重定向通用性差又会增加客户端复杂度;

第一次重定向是客户端将授权服务授权申请的确认动作交给资源拥有者,避免客户端对用户行为与隐私信息的过度参与,保证受保护资源的最终归属权与委托权都是属于资源拥有者的;

第二次重定向是授权服务根据注册与申请的客户端重定向 URI,携带授权码重定向回客户端,告知资源拥有者与客户端授权申请通过,并保持资源拥有者与客户端之间不断开连接,不然资源拥有者在确认授权申请后就会一直处于等待状态;

因为两次重定向都是通过前端信道完成的,告知客户端授权申请通过后,客户端可以使用后端信道发起令牌申请,避免访问令牌暴露在前端,减少受攻击面。

相关推荐
狂师5 分钟前
啥是AI Agent!2025年值得推荐入坑AI Agent的五大工具框架!(新手科普篇)
人工智能·后端·程序员
星辰大海的精灵7 分钟前
使用Docker和Kubernetes部署机器学习模型
人工智能·后端·架构
用户8762191062458 分钟前
【计算机网络】HTTP 版本
http
MikeWe10 分钟前
C++宏的解析:从基础语法到实战场景
后端
向往技术的猫菜15 分钟前
Java必需要会的MySQL知识
后端
拾光拾趣录17 分钟前
无状态协议下的用户状态管理:Web应用如何保持用户登录态
前端·http·https
Frank_zhou18 分钟前
Java代码是如何运行起来的
后端
Victor35618 分钟前
MySQL(121)如何处理死锁问题?
后端
亚洲第一中锋_哈达迪18 分钟前
深入剖析 go-zero 分布式缓存
后端
Frank_zhou21 分钟前
多线程-sleep-yield-join
后端