OAuth教程--服务器端应用程序

Author Avatar
Sean Yu 7月 13, 2018
  • 在其它设备中阅读本文章

本文是oauth.com上的教程的翻译。(原文地址

服务器端应用程序是处理OAuth 2服务器时遇到的最常见的应用程序类型。这些应用程序在Web服务器上运行,其中应用程序的源代码不可供公众使用,因此他们可以保持其客户端秘钥的机密性。

下图说明了用户与正在与客户端通信的浏览器进行交互的典型示例。客户端和API服务器之间具有单独的安全通信通道。用户的浏览器从不直接向API服务器发出请求,所有内容都先通过客户端。

应用程序的服务器与API通信

服务器端应用程序使用authorization_code授权类型。在此流程中,在用户授权应用程序之后,应用程序接收“授权码”,然后它可以交换访问令牌。

授权码授予

授权码是客户端将为访问令牌交换的临时代码。代码本身从授权服务器获得,其中用户有机会查看客户端请求的信息,并批准或拒绝该请求。

授权码流程与其他授权类型相比具有一些优势。当用户授权应用程序时,会带着URL中的临时代码返回应用程序。应用程序有这个代码来交换访问令牌。当应用程序发出访问令牌请求时,该请求将使用客户端密钥进行身份验证,从而降低攻击者拦截授权码并自行使用它的风险。这也意味着访问令牌永远不会被用户看到,因此这是将令牌传递回应用程序的最安全方式,从而降低令牌泄露给其他人的风险。

Web流程的第一步是请求用户授权。这是通过创建用户单击的授权请求链接来完成的。

授权URL通常采用以下格式:

https://authorization-server.com/oauth/authorize
?client_id=a17c21ed
&response_type=code
&state=5ca75bd30
&redirect_uri=https%3A%2F%2Fexample-app.com%2Fauth

确切的URL endpoint将由您要连接的服务指定,但参数名称将始终相同。

请注意,在接受服务之前,您很可能首先需要在服务中注册重定向URL。这也意味着您无法根据请求更改重定向网址。相反,您可以使用该state参数来自定义请求。

用户访问授权页面后,该服务会向用户显示请求的说明,包括应用程序名称,范围等。如果用户单击“批准”,则服务器将使用您在查询字符串参数中提供的“code”和相同的“state”参数重定向回应用程序。请务必注意,这不是访问令牌。您可以使用授权码执行的唯一操作是发出获取访问令牌的请求。

授权授予参数

以下参数用于授予授权。您应该使用以下参数构建一个查询字符串,并将其附加到从其文档中获取的应用程序的授权endpoint后。

response_type=code
response_type设置为code表示您希望将授权码作为响应。

client_id
client_id是您的应用的标识符。首次向服务注册您的应用时,您将收到client_id。

redirect_uri (可选的)
redirect_uri是可选的,但强烈建议你添加。这是您希望在授权完成后将用户重定向到的URL。这必须与您先前在服务中注册的重定向URL相匹配。

scope (可选的)
包括一个或多个范围值(以空格分隔)以请求其他访问级别。它的值取决于特定服务。

state (推荐的)
state参数有两个功能。当用户被重定向回您的应用程序时,您在state中包含的任何值都将包含在重定向中。这使您的应用程序有机会在用户被定向到授权服务器和再次返回之间保留数据,例如使用state参数作为会话密钥。也可用于指示在授权完成后应用中要执行的操作,例如,指示在授权后应该重定向到应用的哪个页面。也可以作为CSRF保护机制。当用户重定向回您的应用程序时,请仔细检查state值是否与您最初设置的值相匹配。这将确保攻击者无法拦截授权流程。

将所有这些查询字符串参数组合到登录URL中,并将用户的浏览器定向到那里。通常,应用程序会将这些参数放入登录按钮,或者从应用程序自己的登录URL发送重定向到此URL。

用户批准该请求

在用户进入服务并看到请求后,他们将允许或拒绝该请求。如果他们允许请求,他们将带着查询字符串中的授权码,并被重定向回指定的重定向URL。然后,应用程序需要使用此授权码交换访问令牌。

交换访问令牌的授权码

要使用授权码交换访问令牌,应用程序会向服务的令牌endpoint发出POST请求。请求将具有以下参数。

grant_type (需要)
grant_type参数必须设置为“authorization_code”。

code (需要)
查询字符串参数“code”中存放从授权服务器接收的授权码。

redirect_uri (可能需要)
如果重定向URL包含在初始授权请求中,则它也必须包含在令牌请求中,并且必须相同。某些服务支持注册多个重定向URL,有些服务需要在每个请求上指定重定向URL。请查看服务的文档以了解具体信息。

客户端验证(必填)

该服务将要求客户端在发出访问令牌请求时进行身份验证。通常,服务通过HTTP Basic Auth来进行客户端身份验证,并使用客户端的client_id和client_secret。但是,某些服务通过接受client_id和client_secret作为POST body参数来支持身份验证。检查服务的文档以找出服务所期望的内容,因为OAuth 2.0规范将此决定留给了服务。

示例流程

以下逐步说明示例使用授权代码授予类型。

步骤:

  • 使用应用程序的客户端ID,重定向URL和state参数创建登录链接
  • 用户看到授权提示并批准该请求
  • 用户带着授权码重定向回应用程序的服务器
  • 应用程序使用授权码交换访问令牌

应用程序启动授权请求

应用程序通过制作包含ID,scope和state的URL来启动流程。该应用程序可以将其放入<a href="">标签中。

<a href="https://authorization-server.com/oauth/authorize
?response_type=code&client_id=mRkZGFjM&state=5ca75bd30">
Connect Your Account</a>

用户批准该请求

在被定向到auth服务器后,用户会看到下图所示的授权请求。如果用户批准该请求,他们将带着授权码和state参数重定向回应用程序。

示例授权请求

服务将用户重定向回应用程序

服务将用户重定向回发出请求的应用程序。重定向将在URL中包含“code”和原始的“state”参数。

https://example-app.com/cb?code=Yzk5ZDczMzRlNDEwY&state=5ca75bd30

应用程序使用授权吗交换访问令牌

该应用程序使用授权码,通过向授权服务器发出POST请求来获取访问令牌。

POST /oauth/token HTTP/1.1
Host: authorization-server.com

code=Yzk5ZDczMzRlNDEwY
&grant_type=code
&redirect_uri=https://example-app.com/cb
&client_id=mRkZGFjM
&client_secret=ZGVmMjMz

auth服务器验证请求,并返回访问令牌和访问令牌过期时使用的刷新令牌。

响应:

{
  "access_token": "AYjcyMzY3ZDhiNmJkNTY",
  "refresh_token": "RjY2NjM5NzA2OWJjuE7c",
  "token_type": "bearer",
  "expires": 3600
}

可能的错误

有几种情况下,您可能会在授权期间收到错误响应。

错误会通过在返回的重定向URL的查询字符串提示。重定向URL总会有一个错误参数,也可能包含error_description和error_uri。

例如:
https://example-app.com/cb?error=invalid_scope

尽管服务器返回error_description密钥,但错误描述并不打算显示给用户。相反,您应该向用户显示您自己的错误消息。这允许您告诉用户采取适当的措施来纠正问题,并且如果您正在构建多语言网站,还可以让您有机会本地化错误消息。

无效的重定向网址

如果提供的重定向URL无效,则auth服务器不会重定向到它。相反,它可以向用户显示描述问题的信息。

无法识别 client_id

如果无法识别客户端ID,则auth服务器不会重定向用户。相反,它可能会显示一条描述问题的信息。

用户拒绝该请求

如果用户拒绝授权请求,则服务器会将用户重定向包含error=access_denied查询字符串的重定向URL ,并且不会出现code字段。由应用程序决定此时向用户显示的内容。

无效的参数

如果一个或多个参数无效,例如缺少必需值,或者response_type参数错误,服务器将重定向到重定向URL并包含描述问题的查询字符串参数。

error参数的其他可能值为:

  • invalid_request:请求缺少必需参数,包含无效参数值,或者格式错误。
  • unauthorized_client:客户端无权使用此方法请求授权码。
  • unsupported_response_type:授权服务器不支持使用此方法获取授权码。
  • invalid_scope:请求的范围无效,未知或格式错误。
  • server_error:授权服务器遇到意外情况,导致无法完成请求。
  • temporarily_unavailable:由于服务器临时过载或维护,授权服务器当前无法处理请求。

此外,服务器可以包括参数error_description和error_uri关于错误的附加信息。

用户体验考虑事项

为了使授权代码授权生效,授权页面必须出现在用户熟悉的Web浏览器中,并且不得嵌入到iframe弹出窗口或移动到应用程序中的嵌入式浏览器中。因此,对于传统的“Web应用程序”来说,用户已经在Web浏览器中并且重定向到服务器的授权页面的这种操作,是最适用的。

安全考虑

授权码授权是为可以保护其客户端ID和密钥的客户端设计的。因此,最适合不提供其源代码的在服务器上运行的网络应用程序。

如果应用程序想要使用授权代码授权但无法保护其密钥(即本机移动应用程序),则在请求交换访问令牌的授权代码时就不需要客户端密钥。但是,某些服务不接受没有客户端密钥的授权码交换,因此本机应用程序可能需要为这些服务使用备用方法。

尽管OAuth 2.0规范并不特别要求重定向URL使用TLS加密,但我强烈建议您使用它。不需要的唯一原因是因为部署SSL网站对许多开发人员来说仍然是一个障碍,这将阻碍规范的广泛采用。有些API确实需要https作为重定向端点,但许多API仍然没有这样要求。