OAuth 2.0 的 4 种模式

2023-01-27, 星期五, 21:53

Cyber SecurityDev

OAuth 2.0 的场景中有四个角色:

  • Resource Owner,受保护资源的所有者,一般是终端用户;
  • Resource Server,资源托管者,提供访问这些受保护资源的 API;
  • Client,客户端:需要请求受保护资源;
  • Authorization Server,鉴权服务:提供用户认证与令牌签发服务,不过今天的讨论中可以由 Resource Server 代劳;

今天的场景中 Resource Server 是一家服务提供商 auth.comClient 则是第三方应用 cool.appcool.app 需要临时向 auth.com 请求一些受保护的资源,此时需要证明 auth.com 的某个用户 A 即 Resource Owner 确实授权了这一操作。

至于为什么 OAuth 2.0 能顺便实现第三方登录的效果,就会涉及到 OpenID Connect (OIDC) 的内容,当然简单点也可以是 cool.app 在获取用户授权后顺便请求了 auth.com/user 接口。

在现实场景中 auth.com 一般对应各种第三方登录服务商(Apple、Microsoft、Google、WeChat 什么的),cool.app 则通常是我们自己开发的应用。无论使用哪一个 OAuth 2.0 应用模式,cool.app 都需要在 auth.com 处注册并取得身份标识,通常称为 CLIENT_IDCLIENT_SECRET

Authorization Code Flow,授权码模式

这是 Web 应用和移动 APP 上最常见的模式,用户 A 在 cool.app 的页面上点击一个授权链接,前往:

https://auth.com/authorize?
  response_type=code&
  client_id=CLIENT_ID&
  redirect_uri=REDIRECT_URL&
  scope=read

response_type=code 表明使用的是授权码模式,scope=read 表明了请求权限的范围。

用户跳转到 auth.com 后可以声明允许或拒绝授权。无论如何,用户都将被重定向到 redirect_uri 地址。允许授权时的目的地可能长下面这样,AUTHORIZATION_CODE 就是 auth.com 发放的授权码。

https://cool.app/authorize/callback?code=AUTHORIZATION_CODE

接下来所有的工作需要保密,所以就来到了后端服务中。cool.app 需要根据授权码请求真正的令牌,比如向 auth.com 的令牌服务(通常是 /oauth/tokon 端点)发起请求:

{
    "client_id": CLIENT_ID,
    "client_secret": CLIENT_SECRET,
    "grant_type": "authorization_code",
    "code": AUTHORIZATION_CODE,
    "callback_uri": CALLBACK_URL
}

auth.com 在确认无误后将向 CALLBACK_URL 指定的接口颁发令牌,比如下面这个就是 GitHub 发的:

Accept: application/json
{
  "access_token": "gho_16C7e42F292c6912E7710c838347Ae178B4a",
  "scope": "repo,gist",
  "token_type": "bearer"
}

接下来就该干嘛干嘛了。

curl -H "Authorization: Bearer ACCESS_TOKEN" https://api.github.com/user

Implicit Flow with Form Post,隐藏模式

如果 cool.app 是一个纯前端应用,就不能使用 OAuth 了吗?非也。

https://auth.com/oauth/token?
  response_type=token&
  client_id=CLIENT_ID&
  redirect_uri=REDIRECT_URL&
  scope=read

注意到这里跳转 URL 中 response_type 变成了 tokenauth.com 在返回时会直接在 URL 中携带令牌。因为这时候令牌是明文的,一般会放在 URL 的 Fragment 部分,免得通过 HTTP 请求一起发出去了,稍稍保证一点安全性。

https://cool.app/authorize/callback#token=ACCESS_TOKEN

Resource Owner Password Flow,密码模式

RFC 6749 让你把在 auth.com 的帐号密码告诉 cool.app 好让它去申请令牌?

Client Credentials Flow,客户端凭证模式

客户发现他们在 UI 上花掉的预算是核心功能的 4 倍,所以 cool.app is dead, long live the cool.cli

cool.cliauth.com 发起了 Web 请求:

curl https://auth.com/oauth/token?
  grant_type=client_credentials&
  client_id=CLIENT_ID&
  client_secret=CLIENT_SECRET

这里直接提供了 cool.cli 的注册信息,没有用户什么事,所以这里的凭证是针对客户端而不是用户的。