OAuth2的四种认证模式

7/25/2024 6:05:07 PM
794
0

一、授权模式

1.1、授权码模式(authorization code)

授权码(authorization code)方式,指的是 第三方应用先申请一个授权码,然后再用该码获取令牌。

1.2、简化模式(implicit)(已经过时,废弃) 

有些 Web 应用是纯前端应用,没有后端。这时就不能用上面的方式了,必须将令牌储存在前端。RFC 6749 就规定了第二种方式, 允许直接向前端颁发令牌。这种方式没有授权码这个中间步骤,所以称为(授权码)“隐藏式”(implicit)。

1.3、密码模式(resource owner password credentials)

如果你高度信任某个应用,RFC 6749 也允许用户把用户名和密码,直接告诉该应用。该应用就使用你的密码,申请令牌,这种方式称为"密码式"(password)。

1.4、客户端模式(client credentials)

最后一种方式是凭证式(client credentials), 适用于没有前端的命令行应用,即在命令行下请求令牌。

二、授权码模式详解

授权码模式(authorization code)是功能最完整、流程最严密安全的授权模式。它的特点就是 通过客户端的 后台服务器,与"服务提供商"的认证服务器进行互动。

注意这种方式适用于那些有后端的 Web 应用。 授权码通过前端传送,令牌则是储存在后端,而且所有与资源服务器的通信都在后端完成。

微信公众号授权流程即采用这种方式。

OIDC是基于OAuth2的授权码模式实现的

2.1 授权码模式流程如下:

1)用户访问客户端,客户端将用户导向认证服务器。

2)用户选择是否给予客户端授权。

3)假设用户给予授权,认证服务器将用户导向客户端事先指定的"重定向URI"(redirection URI),同时附上一个授权码(每个用户的授权码不同)。

4)客户端收到授权码,附上早先的"重定向URI",向认证服务器申请令牌。这一步是在客户端的  后台服务器 上完成的,对用户不可见。

5)认证服务器核对了授权码和重定向URI,确认无误后,向客户端发送访问令牌(access token)和更新令牌(refresh token)。

从上述的流程描述可知,只有第 2 步需要用户进行授权操作,之后的流程都是在客户端的后台和认证服务器后台之前进行"静默"操作,对于用户来说是无感知的。

下面是上面这些步骤所需要的参数。

第 1 步骤中,客户端申请认证的URI,包含以下参数:

  • response_type:表示授权类型, 必选项,此处的值固定为"code"
  • client_id:表示客户端的ID, 必选项
  • redirect_uri:表示重定向URI,可选项
  • scope:表示申请的权限范围,可选项
  • state:表示客户端的当前状态,可以指定任意值,认证服务器会原封不动地返回这个值。

示例

A 网站提供一个链接,用户点击后就会跳转到 B 网站,授权用户数据给 A 网站使用。下面就是 A 网站跳转 B 网站的一个示意链接:

  https://b.com/oauth/authorize?response_type=code&client_id=CLIENT_ID&redirect_uri=CALLBACK_URL&scope=read

上面 URL 中:

response_type参数表示要求返回授权码( code);

client_id参数让 B 网站知道是谁在请求;

redirect_uri参数是 B 网站接受或拒绝请求后的跳转网址;

scope参数表示要求的授权范围(这里是只读)。

第 3 步骤中,服务器回应客户端的URI,包含以下参数:

  • code:表示授权码, 必选项。该码的有效期应该很短, 通常设为10分钟,客户端只能使用该码一次,否则会被授权服务器拒绝。该码与客户端ID和重定向URI,是一一对应关系。
  • state:如果客户端的请求中包含这个参数,认证服务器的回应也必须一模一样包含这个参数。

示例

在第 2 步骤用户表示同意之后,这时 B 网站就会跳回 redirect_uri参数指定的网址。跳转时,会传回一个授权码,就像下面这样。

https://a.com/callback?code=AUTHORIZATION_CODE 

上面 URL 中, code参数就是授权码。

第 4 步骤中,客户端向认证服务器申请令牌的HTTP请求,包含以下参数:

  • grant_type:表示使用的授权模式, 必选项,此处的值固定为"authorization_code"。
  • code:表示上一步获得的授权码, 必选项
  • redirect_uri:表示重定向URI, 必选项,且必须与A步骤中的该参数值保持一致。
  • client_id:表示客户端ID, 必选项

示例

在第 3 步骤中,A 网站拿到授权码以后,就可以在后端,向 B 网站请求令牌。

  https://b.com/oauth/token? client_id=CLIENT_ID& client_secret=CLIENT_SECRET& grant_type=authorization_code& code=AUTHORIZATION_CODE& redirect_uri=CALLBACK_URL

上面 URL 中:

client_id参数和 client_secret参数用来让 B 确认 A 的身份( client_secret参数是保密的,因此只能在后端发请求);

grant_type参数的值是 AUTHORIZATION_CODE,表示采用的授权方式是授权码;

code参数是上一步拿到的授权码;

redirect_uri参数是令牌颁发后的回调网址。

第 5 步骤中,认证服务器发送的HTTP回复,包含以下参数:

  • access_token:表示访问令牌,必选项。
  • token_type:表示令牌类型,该值大小写不敏感,必选项,可以是bearer类型或mac类型。
  • expires_in:表示过期时间,单位为秒。如果省略该参数,必须其他方式设置过期时间。
  • refresh_token:表示更新令牌,用来获取下一次的访问令牌,可选项。
  • scope:表示权限范围,如果与客户端申请的范围一致,此项可省略。h

 

  HTTP/1.1 200 OK Content-Type: application/json;charset=UTF-8 Cache-Control: no-store Pragma: no-cache {"access_token":"ACCESS_TOKEN","token_type":"bearer","expires_in":2592000,"refresh_token":"REFRESH_TOKEN","scope":"read","uid":100101,"info":{...} }

后续

当客户端(第三方应用程序)拿到访问资源服务器的令牌时,便可以使用这个令牌进行资源访问了。例如:拿到了access_token  和user_id (id_token之类的)请求用户详细数据

如何发送给资源服务器这个问题并没有在 RFC6729 文件中定义,而是作为一个单独的  RFC6750文件中独立定义了。这里做以下简单的介绍,主要有三种方式如下:

  1. URI Query Parameter
  2. Authorization Request Header Field
  3. Form-Encoded Body Parameter

Authorization Request Header Field,因为在HTTP应用层协议中,专门有定义一个授权使用的Request Header,所以也可以使用这种方式:

  GET /resource HTTP/1.1 Host: server.example.com Authorization: Bearer mF_9.B5f-4.1JqM

其中"Bearer "是固定的在access_token前面的头部信息。

令牌的刷新

为了防止客户端使用一个令牌无限次数使用,令牌一般会有过期时间限制,当快要到期时,需要重新获取令牌,如果再重新走授权码的授权流程,对用户体验非常不好,于是 OAuth 2.0 允许用户自动更新令牌。

具体方法是,B 网站颁发令牌的时候,一次性颁发两个令牌,一个用于获取数据,另一个用于获取新的令牌(refresh token 字段)。令牌到期前,用户使用 refresh token 发一个请求,去更新令牌。

2.2 隐藏式(已经过时,废弃使用

简化模式(Implicit Grant)是一种适用于  无后端支持 的客户端应用(如单页面应用,SPA)的授权方式。访问令牌直接返回给客户端,用于访问用户的资源。以下以  第三方单页面应用为例,解析简化模式的流程。

流程步骤

  1. 用户访问单页面应用并请求登录
    用户打开 第三方单页面应用,尝试访问需要授权的资源(例如用户个人信息、数据等)。或者应用引导用户进入授权页面

  2. 跳转到认证服务器进行登录
    应用检测到用户未登录,会将用户引导至认证服务器的授权页面。此时,应用会携带 Client ID和重定向 URI 等参数,表明这是一个授权请求。

            https://b.com/oauth/authorize?response_type=token&client_id=CLIENT_ID&redirect_uri=CALLBACK_URL&scope=read

    上面 URL 中, response_type参数为 token,表示要求直接返回令牌

     

  3. 用户登录并授权
    用户在认证服务器的页面完成登录操作后,系统会展示一个授权请求页面,说明单页面应用需要的权限范围(例如访问用户信息)。用户确认授权后,认证服务器会生成一个 访问令牌(Access Token)

  4. 认证服务器直接返回访问令牌
    认证服务器将访问令牌附带在重定向 URI 的哈希片段中,直接返回给单页面应用的前端客户端。例如:

            https://example.com/callback#access_token=xyz123&token_type=bearer&expires_in=3600
    注意,令牌的位置是 URL 锚点(fragment),而不是查询字符串(querystring),这是因为 OAuth 2.0 允许跳转网址是 HTTP 协议,因此存在"中间人攻击"的风险,而浏览器跳转时,锚点不会发到服务器,就减少了泄漏令牌的风险。
  5. 单页面应用提取访问令牌并存储
    前端应用从重定向 URI 中提取出访问令牌(通常通过 JavaScript 处理),并将其存储在内存中或短期存储中(如浏览器的 sessionStorage)。

  6. 使用访问令牌请求资源服务器
    单页面应用使用访问令牌向资源服务器发起请求,获取用户的授权数据(如用户名、头像等)。

  7. 资源服务器返回授权数据
    资源服务器验证令牌合法性后,返回用户的授权数据给单页面应用。

  8. 完成登录并显示用户信息
    单页面应用根据返回的数据更新界面,显示用户的登录信息和授权内容。

2.3 密码模式

密码模式(Resource Owner Password Credentials Grant)允许用户直接将用户名和密码提供给客户端,以获取访问令牌。它的安全性较低,一般仅在高度信任的环境中使用,比如内部系统。以下以 第三方网站的管理系统为例,解析密码模式的流程。

流程步骤

  1. 用户在客户端输入凭据
    用户打开客户端应用(如第三方内部管理系统),并输入用户名和密码尝试登录。

  2. 客户端将凭据发送至认证服务器
    客户端应用将用户输入的 用户名密码,连同自身的 Client IDClient Secret,通过后台请求发送到认证服务器。

    POST /oauth/token HTTP/1.1
    Host: auth-server.com
    Content-Type: application/x-www-form-urlencoded
    
    grant_type=password
    username=user123
    password=pass123
    client_id=client_id_example
    client_secret=client_secret_example
    
  3. 认证服务器验证凭据
    认证服务器接收到请求后,会:

    • 验证 用户名密码 是否正确。
    • 检查 Client IDClient Secret 是否有效。
    • 如果所有验证通过,则生成一个访问令牌(Access Token)。
  4. 认证服务器返回访问令牌
    验证通过后,认证服务器返回访问令牌(Access Token)给客户端。

    {
        "access_token": "xyz123",
        "token_type": "bearer",
        "expires_in": 3600
    }
    
  5. 客户端使用令牌请求资源服务器
    客户端携带访问令牌,向资源服务器发起请求,获取用户的授权数据或受保护的资源。

    GET /userinfo HTTP/1.1
    Host: resource-server.com
    Authorization: Bearer xyz123
    
  6. 资源服务器返回授权数据
    资源服务器验证令牌的合法性后,返回用户授权的资源(如用户信息或操作权限)。

  7. 完成授权流程并展示数据
    客户端接收到用户数据后,展示相关内容(如登录成功后的用户信息)。

2.4  客户端模式 

客户端模式(Client Credentials Grant)用于服务之间的授权,不涉及用户参与。典型场景是服务端之间的通信,例如后台服务器与第三方 API 的对接。以下以 第三方网站 和 资源服务器 的对接为例,解析客户端模式的流程。

典型应用:使用公众号appid和secret 获取AccessToken 并通过 AccessToken调用微信公众号的各种接口

流程步骤

  1. 第三方网站向认证服务器发起请求
    第三方网站 的后台服务器向认证服务器发送请求,附带自身的 Client IDClient Secret
    https://oauth.b.com/token?
      grant_type=client_credentials&
      client_id=CLIENT_ID&
      client_secret=CLIENT_SECRET

    上面 URL 中,grant_type参数等于client_credentials表示采用凭证式,client_idclient_secret用来让 B 确认 A 的身份。

  2. 认证服务器验证客户端身份
    认证服务器验证客户端的 Client IDClient Secret 是否正确,确认客户端的合法性。
  3. 认证服务器返回访问令牌
    验证通过后,认证服务器向 第三方网站 返回访问令牌(Access Token)。
  4. 第三方网站使用访问令牌访问资源服务器
    第三方网站 使用获取的访问令牌向资源服务器发起请求,获取所需的资源或数据(如服务状态、统计数据等)。
    GET /userinfo HTTP/1.1
    Host: resource-server.com
    Authorization: Bearer xyz123
  5. 资源服务器返回授权数据
    资源服务器验证令牌合法性后,返回请求的数据给 第三方网站
 

 

全部评论



提问