09. 两条腿的 OAuth:客户端模式

什么是客户端模式

客户端模式是一种十分特殊的授权模式,不同于我们在前面小节讲到的三种授权模式(授权码模式、简化模式、密码模式),客户端模式不需要用户的参与,这是一种服务器与服务器(server-to-server)之间的交互模式。这种模式也被形象地称为“两条腿的 OAuth(two-legged OAuth或者2LO)”,因为相对于其它三种模式模式,这种模式少了终端用户这个角色的参与,在这三种模式下都解决同一个问题——客户端试图代表终端用户访问终端用户托管在资源服务器上的资源。
 
这种模式放在OAuth中让人比较困惑,我们在前文中一再强调,OAuth是一个授权访问的框架,但是在这种模式下甚至没有委托人即终端用户的参与。很多博客中牵强地称在这种场景下客户端即是资源拥有者,它代表自己获得授权服务器的授权许可,获取托管在资源服务器上的资源。但是在一般场景下,客户端模式下的资源往往不属于任何客户端,而是一种通用的能力。
 
如下图所示,我们以一个示例解释一下客户端模式的应用场景。你所在的公司有一个门户网站,你现在有一个需求,需要向登录和使用门户网站的同学展示未来三天的天气状况。有一个天气网站提供了这样的功能,天气API不用关心当前是谁登录你的门户网站,天气数据是一种通用的数据,它不属于任何用户,在同一区域的用户看到的天气数据应该是一样的。因此天气网站提供了你使用客户端模式获取天气数据的API。
 
百度AI开放平台是一个实际的良好的运用和实践客户端模式的例子(https://ai.baidu.com/ai-doc/REFERENCE/Ck3dwjhhu)。它提供了很多的开放能力,比如语音识别、语音合成、人脸识别、图像识别等功能,开放这些API的原因是它可以为企业实现盈利创造价值——比如对于一些没有能力进行人脸识别的公司或企业,可以选择注册成为百度AI开放平台的客户端,然后使用和购买百度AI的人脸识别功能。
是的API具有巨大的经济价值,如果你对这个话题感兴趣,你可以阅读《The Power of the API Economy》(https://www.redbooks.ibm.com/redpapers/pdfs/redp5096.pdf)这本书
客户端模式的时序图如下图所示:
  1. 客户端应用程向授权服务器的令牌端点发起令牌请求。其中客户端ID和客户端密钥包含在Authorizaion Header头中,Basic后面的内容是对字符串client_id:client_secret Base 64编码后的结果。
  2. 授权服务器校验客户端信息的有效性,向客户端发放访问令牌。
  3. 客户端携带访问令牌向资源服务器发起API调用请求。
  4. 资源服务器向客户端响应资源。
注意的是不管授权服务器是否支持刷新令牌(这是我们在四种授权模式之后讨论的另外一种模式),在客户端模式下授权服务器都不会发放刷新令牌,它必须重复上面时序图的第一到第四步,重新获取一个访问令牌。这是因为在客户端模式下,客户端没有“不在现场的理由”。它作为“资源的拥有者”,当它需要资源时必须且只可能“在现场”。

令牌请求

请求参数

客户端向授权服务器的令牌端点发出POST请求,使用application/x-www-form-urlencodedformat编码的方式传递以下参数。
  1. grant_type:必须参数。在客户端模式下该值必须设置为client_credentials。
  2. scope:可选参数。表示请求授权的访问权限范围,一般是以空格分隔、区分大小写的字符串列表,例如“profile:read profile:write”。
  3. 客户端认证信息:必须参数。在客户端模式的令牌请求中必须携带客户端认证相关的信息。一般的都使用RFC 2617定义的HTTP BASIC身份认证的方式,这种技术需要客户端发送带有“Authorization”头信息的HTTP请求,Authorization头信息由三部分组成——固定单词“Basic”,后面紧跟一个空格,最后一部分是对client_id、冒号(英文)、client_secret组合而成的字符串(即client_id:client_secret)进行Base64编码后的结果,下面是一个Authorization头信息的示例:
    Authorization Basic MTIzNDU6SGlzSyQyMTFGbWNj
另外一种方式是直接在请求中传递client_id和client_secret(百度AI开放平台就是使用这种方式),尽管上面提到的HTTP BASIC身份认证方式很简单,但是一般认为它比这种方式要更安全,所以更推荐前者,但这具体取决于授权服务器的实现。

请求示例

下面的代码段展示了使用HTTP BASIC身份认证方式的令牌请求示例。
POST /token HTTP/1.1
Host: authorizationserver.com
Authorization: Basic [encoded CLIENT_ID CLIENT_SECRET] 
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials
&scope=[SCOPE]

下面是直接在请求中传递client_id和client_secret进行身份认证的令牌请求示例。
POST /oauth/2.0/token HTTP/1.1
Host: aip.baidubce.com
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials
&client_id=【百度云应用的AK】
&client_secret=【百度云应用的SK】'

令牌响应

成功响应

成功响应参数

如果令牌请求是有效的,授权服务器将向客户端返回以下参数。
  1. access_token:(必须)授权服务器颁发的访问令牌,客户端最终使用该访问令牌请求资源API。
  2. token_type:(必须)授权服务器颁发的令牌的类型。一般该值是“bearer”。如果你对Bearer Token感兴趣,你可以阅读RFC 6750文档(https://datatracker.ietf.org/doc/html/rfc6750)。
  3. expires_in:(可选)以秒为单位的访问令牌的生存期。该参数为非必需参数,如果缺省这个参数,授权服务器必需以其他方式告知客户端令牌的剩余生命周期。
  4. scope:(可选)表示授权服务器授予的访问权限范围。仅当授予的范围与令牌请求时的范围不同(一般是令牌请求范围的子集)时才需要授权响应包含该参数,否则该参数是可选的。

成功响应示例

下面是令牌成功响应的示例:
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-storePragma: no-cache

{
"access_token":"FMZsA1280SvKeN38111L",
"token_type":"bearer",
"expires_in":3600,
"scope":"profile:read profile:write"
}

错误响应

错误响应参数说明

如果令牌请求因任何原因失败,服务器将返回HTTP 400(错误请求)的状态码,并包含以下参数:
  1. error:error参数是必须的,代表令牌请求错误的原因。用来辅助开发者来定位问题,error通常是以下错误码之一:
    1. invalid_request:令牌请求缺少必要的参数,包含不支持的参数值、重复参数、包含多个凭据、使用多种机制对客户端进行身份验证,或者格式不正确。
    2. invalid_client:由于某些原因客户端身份认证失败(例如,未知客户端、没有客户端身份认证信息或不支持的身份认证方法)。
    3. invalid_grant:提供的授权类型或刷新令牌无效、过期、已吊销等,或者与授权请求中使用的重定向URI不匹配。
    4. unauthorized_client:经过身份验证的客户端无权使用这种授权类型。
    5. unsupported_grant_type:授权服务器不支持这种授权类型。
    6. invalid_scope:请求的作用域无效、未知、格式不正确或超出了资源所有者授予的作用域。
  2. error_description:(可选)描述错误原因的可读消息,用于帮助客户端开发人员了解发生的错误。
  3. error_uri:(可选)有关描述错误详细信息的网页地址。

错误响应示例

错误响应示例如下:
  HTTP/1.1 400 Bad Request    
  Content-Type: application/json;charset=UTF-8    
  Cache-Control: no-store 
  Pragma: no-cache    

{
"error":"invalid_request"
}

使用客户端模式保护微服务安全

在微服务中,服务之间通信的频率更高。通信可以发生在同一信任域内的两个微服务之间,也可以发生在两个信任域之间。有三种通用的方式来保护服务之间的通信:
  1. 网络安全模式。这种模式完全依赖网络安全,它没有实施额外的安全策略,网络安全确保网络外围没有人可以拦截通信。
  2. 双向mTLS通信。这是目前最主流的身份验证方式。在这种模式下每个微服务都携带一对公钥/私钥,并使用该密钥对通过mTLS向接收方微服务进行身份验证。mTLS允许通信中的每个微服务识别其他微服务。
  3. OAuth 2.0客户端模式。客户端模式可以用于系统到系统的身份验证。
 

总结

  • 客户端授权类型虽然是最简单的一种授权类型,但它仍然是一种应用广泛的授权类型。这种授权类型只有两种参与角色——客户端应用程序和授权服务器。客户端应用程序直接向授权服务器发起令牌请求和资源调用请求。百度AI开放平台是一个很好的运用和实践客户端模式例子(https://ai.baidu.com/ai-doc/REFERENCE/Ck3dwjhhu)。
  • 在微服务领域服务和服务之间的通信频率很高,我们可以通过客户端模式来进行服务间的认证从而保障微服务安全。
到此为止我已经向你介绍了在OAuth 2.1中仍然被保留和活跃的两种授权模式——授权码模式和客户端模式。它们经过了大量的生产实践的验证并且做了很多与时俱进的改进,因此你可以放心地将其应用在生产环境中。但是无论如何,在HTTPS之上使用这两种模式仍然是最佳实践。在下一小节我将向你介绍OAtuh 2.0中定义的另外两种授权模式——简化模式和密码模式。
 
 
posted @ 2023-05-07 11:28  小米粥|  阅读(107)  评论(0)    收藏  举报