从0开始构建一个Oauth2Server服务 4
构建服务器端应用程序
以下分步示例说明了将授权代码流与 PKCE 结合使用。
开始
高级概述是这样的:
- 使用应用程序的客户端 ID、重定向 URL、状态和 PKCE 代码质询参数创建登录链接
- 用户看到授权提示并批准请求
- 使用授权码将用户重定向回应用程序的服务器
- 该应用程序交换访问令牌的授权代码
App发起授权请求
该应用程序通过制作包含客户端 ID、范围、状态和 PKCE 代码验证程序的 URL 来启动流程。该应用程序可以将其放入<a href="">
标签中。
<a href="https://authorization-server.com/oauth/authorize
?response_type=code&client_id=mRkZGFjM&state=5ca75bd30
&scope=photos
&code_challenge_method=S256
&code_challenge=hKpKupTM391pE10xfQiorMxXarRKAHRhTfH_xkGf7U4">
Connect Your Account</a>
请注意,这不是您的应用程序正在进行的 HTTP 调用,而是用户单击以将其浏览器重定向到 OAuth 服务器的 URL。
用户批准请求
在被定向到授权服务器后,用户会看到如下图所示的授权请求。如果用户批准请求,他们将连同授权码和状态参数一起被重定向回应用程序。
示例授权请求
该服务将用户重定向回应用程序
该服务发送一个重定向标头,将用户的浏览器重定向回发出请求的应用程序。重定向将在 URL 中包含一个“代码”和原始“状态”。
https://example-app.com/cb?code=Yzk5ZDczMzRlNDEwY&state=5ca75bd30
(这实际上将作为 HTTP 响应从授权服务器发送回用户的浏览器,而不是您的应用程序。此处未显示实际的 HTTP 响应,因为它对您在应用程序中编写的代码并不重要。)
该应用程序交换访问令牌的授权代码
最后,应用程序使用授权代码通过向授权服务器的令牌端点发出 HTTPS 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
&code_verifier=Th7UHJdLswIYQxwSg29DbK1a_d9o41uNMTRmuH0PM8zyoMAQ
授权服务器验证请求并使用访问令牌和可选的刷新令牌进行响应(如果访问令牌将过期)。
服务响应:
{
"access_token": "AYjcyMzY3ZDhiNmJkNTY",
"refresh_token": "RjY2NjM5NzA2OWJjuE7c",
"token_type": "Bearer",
"expires": 3600
}
可能的错误
在几种情况下,您可能会在授权期间收到错误响应。
通过在查询字符串中使用附加参数重定向回提供的重定向 URL 来指示错误。总会有一个错误参数,重定向也可能包括error_description
和error_uri
。
https://example-app.com/cb?error=invalid_scope
尽管服务器返回一个error_description
密钥,但错误描述并不打算显示给用户。相反,您应该向用户显示您自己的错误消息。这使您可以告诉用户采取适当的措施来纠正问题,如果您正在构建多语言网站,还可以让您有机会本地化错误消息。
重定向网址无效
如果提供的重定向 URL 无效,授权服务器将不会重定向到它。相反,它可能会向用户显示一条描述问题的消息。
无法识别client_id
如果无法识别客户端 ID,授权服务器将不会重定向用户。相反,它可能会显示一条描述问题的消息。
用户拒绝请求
如果用户拒绝授权请求,服务器会将用户重定向回error=access_denied
查询字符串中的重定向 URL,并且不会出现任何代码。此时由应用程序决定向用户显示什么。
参数无效
如果一个或多个参数无效,例如缺少所需的值或参数response_type
错误,服务器将重定向到重定向 URL 并包括描述问题的查询字符串参数。error 参数的其他可能值是:
invalid_request
: 请求缺少必需的参数,包括无效的参数值,或者格式不正确。
unauthorized_client
: 客户端无权使用此方法请求授权码。
unsupported_response_type
: 授权服务器不支持通过该方式获取授权码。
invalid_scope
: 请求的范围无效、未知或格式错误。
server_error
: 授权服务器遇到意外情况,无法满足请求。
temporarily_unavailable
: 由于服务器临时过载或维护,授权服务器当前无法处理请求。
此外,服务器可能包括参数error_description
和error_uri
有关错误的附加信息。
用户体验与注意事项
为了确保授权码授予的安全,授权页面必须出现在用户熟悉的 Web 浏览器中,不得嵌入 iframe 弹出窗口或移动应用程序的嵌入式浏览器中。如果它可以嵌入到另一个网站中,用户将无法验证它是合法服务而不是网络钓鱼尝试。
如果应用程序想要使用授权码授予但不能保护其秘密(即本机移动应用程序或单页 JavaScript 应用程序),则在发出请求以交换授权码以获取访问令牌时不需要客户端秘密,并且还必须使用 PKCE。但是,某些服务仍然不支持 PKCE,因此可能无法从单页应用程序本身执行授权流程,并且客户端 JavaScript 代码可能需要具有执行 OAuth 的配套服务器端组件流动代替。