这里用一些通俗的语言,描述OAuth 2.1
中的一些基本概念。
①②③④⑤⑥⑦⑧⑨⑩⑪⑫⑬⑭⑮⑯⑰⑱⑲⑳✕✓✔✖
[TOC]
OAuth 2.1
与OAuth 2.0
的区别OAuth 2.0
定义了四种授权方式
OAuth2.1
删除了该模式OAuth2.1
删除了该模式这里参考了auth0 的文档。
Parameter | Required | Description |
---|---|---|
response_type | 必须 | 您要执行的 OAuth 2.1 流程,code=Authorization Code |
client_id | 必须 | 您的应用程序的 ID |
redirect_uri | 必须 | 回调的地址,如果不填写,会报错,并且填写的内容与设置的一致 |
state | 推荐 | 应用程序添加的一个数值,回调的时候会原封不动的返回。可以判断是不是服务器返回的。 |
scope | 可选 | 请求的范围 |
提示
- 这里不需要客户端密码。
redirect_uri
在标准文档中是可选的,但是这里是必须填写的
在开始此流程之前,您需要随机生成一个 32 位长code_verifier
,并存储在本地。然后运用hash算法s256
加密得到一个code_challenge
。
第一步:先随机生成一个 32 位长的code_verifier
,然后运用hash算法s256
加密得到一个code_challenge
。客户端向认证服务器申请认证码code
, 要带着code_challenge
。
Parameter | Required | Description |
---|---|---|
response_type | 必须 | 您要执行的 OAuth 2.1 流程,code=Authorization Code ,这个可以使用PKCE |
client_id | 必须 | 您的应用程序的 ID |
redirect_uri | 必须 | 回调的地址,如果不填写,会报错,并且填写的内容与设置的一致 |
state | 推荐 | 应用程序添加的一个数值,回调的时候会原封不动的返回。可以判断是不是服务器返回的。 |
code_challenge | 必须 | 对code_verifier 运用hash算法s256 加密得到一个code_challenge 。 |
code_challenge_method | 必须 | 必须填写:S256 ,不然 Spring 提示错误 |
scope | 可选 | 请求的范围 |
提示
- 这里不需要客户端密码。
redirect_uri
在标准文档中是可选的,但是这里是必须填写的
这是输入受限设备用于访问 API 的流程。使用此端点获取设备代码。
Parameter | Required | Description |
---|---|---|
client_id | 必须 | 您的应用程序的 ID |
scope | 可选 | 请求的范围 |
Response Values
Value | Description |
---|---|
device_code | The unique code for the device. When the user visits the verification_uri in their browser-based device, this code will be bound to their session. |
user_code | The code that the user should input at the verification_uri to authorize the device. |
verification_uri | The URL the user should visit to authorize the device. |
verification_uri_complete | The complete URL the user should visit to authorize the device. Your app can use this value to embed the user_code in the URL, if you so choose. |
expires_in | The lifetime (in seconds) of the device_code and user_code . |
interval | The interval (in seconds) at which the app should poll the token URL to request a token. |
POST /oauth2/token
Parameter | Required | Description |
---|---|---|
grant_type | 必须 | 表示您正在使用的流程。对于 Authorization Code,请使用 authorization_code 。 |
client_id | 必须 | 您的应用程序的 ID |
client_secret | 必须 | 您应用的客户端密码。 |
redirect_uri | 必须 | 必须与得到 code 时的一致 |
code | 必须 | 从初始 /authorize 调用收到的授权 Code。 |
Parameter | Required | Description |
---|---|---|
grant_type | 必须 | 表示您正在使用的流程。对于 Authorization Code,请使用 authorization_code 。 |
client_id | 必须 | 您的应用程序的 ID |
redirect_uri | 必须 | 必须与得到 code 时的一致 |
code | 必须 | 从初始 /authorize 调用收到的授权 Code。 |
备注:
- 在这种模式下是不需要 client_secret 的
Parameter | Required | Description |
---|---|---|
grant_type | 必须 | 表示您正在使用的流程。对于 Client Credentials,请使用 client_credentials 。 |
client_id | 必须 | 您的应用程序的 ID |
client_secret | 必须 | 您应用的客户端密码。 |
scope | 可选 | 请求的范围,如果选择 scope,名字就不能写错了 |
按照系统返回的时间间隔,来轮询这个端点,一致最后得到 Access Token
Parameter | Required | Description |
---|---|---|
grant_type | 必须 | 表示您正在使用的流程。对于 Device Authorization,请使用 urn:ietf:params:oauth:grant-type:device_code 。 |
client_id | 必须 | 您的应用程序的 ID |
device_code | 必须 | 先前从 /oauth2/device/code 端点返回的 device code。 |
Parameter | Required | Description |
---|---|---|
grant_type | 必须 | 表示您正在使用的流程。对于刷新令牌,请使用 refresh_token 。 |
client_id | 必须 | 您的应用程序的 ID |
client_secret | 必须 | 您应用的客户端密码。当您的应用程序设置中的令牌端点身份验证方法字段为 Post 或 Basic 时需要。 |
refresh_token | 必须 | 要使用的刷新令牌。 |
scope | 可选 | 以空格分隔的请求范围权限列表。如果未发送,将使用原始范围;否则,您可以请求减少一组范围。 |
这个有待研究
如果刷新令牌已被泄露,请使用此端点使刷新令牌无效。
Parameter | Required | Description |
---|---|---|
client_id | 必须 | 您的应用程序的 ID |
client_secret | 可选 | 您应用的客户端密码。 |
token | 必须 | 您要撤销的刷新令牌。 |
这个流程需要研究一下
OAuth 2.1
流程?决定使用那个流程,跟你的应用程序类型有主要的关系。同时有些参数要考虑,例如 client 端的信任程度,或您希望用户拥有的体验。这里参考了一个网址
这里假设你对OAuth 2.1
中的属于已经很了解:Resource Owner ; Client ; Resource Server ; Authorization Server;User Agent;
,并且知道OAuth 2.0
中的一些流程在OAuth 2.1
中已经取消,并且OAuth 2.1
添加了一些新的安全措施。
Is the Client the Resource Owner?
客户端应用程序是资源所有者吗?可以通过下面几个条件才判断:
API
将输入写入数据库。定时程序是Client
和Resource Owner
,所以它可以通过Client ID
和Client Secret
从授权服务器获取Access Token
。在这种模式下,可以使用:client_credentials
流程。
Is the Client a web app executing on the server?
如果客户端是在服务器上执行的常规 Web 应用程序,那么authorization_code
流程就是您应该使用的流程。
使用authorization_code
,客户端可以得到Access Token
,同时可选择获取一个Refresh Token
。它被认为是最安全的选择,因为Access Token
直接传递到托管客户端的 Web 服务器,而无需通过用户的 Web 浏览器和暴露风险。
在这种模式下,可以使用:authorization_code
流程。
Is the Client a Single-Page App?
如果客户端是单页应用程序 (SPA),即使用 JavaScript 等脚本语言在浏览器中运行的应用程序,则有两个授权选项:
Proof Key for Code Exchange (PKCE)
安全限制的authorization_code
流程。Implicit
流程。但是OAuth2.1
这种流程被删除了。对于大多数情况,我们建议使用带有 PKCE
的authorization_code
流程,因为Access Token
不会在客户端公开(对这句话存疑,可以参考 PKCE 流程),并且此流程可以返回 Refresh Tokens
。
要了解有关此流程如何工作以及如何实施的更多信息,请参阅Authorization Code Flow with Proof Key for Code Exchange (PKCE).
有些程序提供了基于前端的 SDK,例如 Auth0 Single-Page App SDK ,为在 SPA 中使用 PKCE 实现授权代码流提供高级 API。
在这种模式下,可以使用:authorization_code
流程+PKCE
。
Is the Client a Native/Mobile App?
在这种模式下,可以使用:authorization_code
流程+PKCE
。
I have an application that needs to talk to different resource servers
每个授权将使用不同的 audience
,这将在流程结束时产生不同的访问令牌。有关详细信息,请参阅 OAuth 2.0: Audience Information Specification.
可以,但是我要提前了解一些 spring 提供了那些默认的端点。
下面有两个其他系统的文档,可以参考一下
Authorization Code Flow with Proof Key for Code Exchange (PKCE)
如果您的应用程序无法安全地存储客户端认证密码,那么这就是您的授权类型。
当公共客户端(例如,原生和单页 Web 应用程序)请求访问令牌时,如果单独使用Authorization Code
会有一些安全问题,例如:
Native apps
redirects uri
返回的code
Single-page apps
鉴于这些情况,OAuth 2.0
提供了一个授权代码流版本,它使用Proof Key for Code Exchange (PKCE)
(在 OAuth 2.0 RFC 7636 中定义)。
PKCE
的原理PKCE
增强了Authorization Code
流程,流引入了一个由调用应用程序创建的密钥,该密钥可由授权服务器验证;
Code Verifier
:上述密钥被称为Code Verifier
。Code Challenge
:调用应用程通过对Code Verifier
进行转换得到的一个值叫Code Challenge
,这个数值会在请求 code 的时候,通过HTTPS
一起发送给授权服务器。这样一来,恶意攻击者只能截获授权码,而没有验证码他们无法将其换成令牌。
因为 PKCE
增强的授权代码流建立在标准授权代码流之上,所以步骤非常相似。
用户点击登陆
创建一个随机加密的 code_verifier
,并由code_verifier
生成一个 code_challenge
。
重定向到授权服务器,同时将code_challenge
也给传递过去。
授权服务器将用户重定向到登录和授权提示。
用户使用配置的登录选项之一进行身份验证,并且可能会看到一个同意页面,其中列出了将授予应用程序的权限。
授权服务器存储 code_challenge
并将授权 code
通过重定向返回给用户的应用程序。
将code
和 code_verifier
(在步骤 2 中创建)发送到授权服务器
授权服务器验证 code_challenge
和 code_verifier
授权服务器返回 ID Token
和Access Token
(以及可选的Refresh Token
)。
您的应用程序可以使用Access Token
调用 API
以访问有关用户的信息。
简单来说就是获取 Token 过程中,利用两个数值比较来验证请求者是否是最终用户,防止攻击者盗用 Token。 它提高了公有云环境下的单页面运用或 APP 获取 Token 的安全性,也能应用在私有云环境里。我们可利用它来实现 SSO。
具体步骤简单描述如下:
第一步:先随机生成一个 32 位长的code_verifier
,然后运用hash算法s256
加密得到一个code_challenge
。js 算法实现可参考这里;
第二步:客户端向 oauth2 认证服务器申请认证码 code, 并带着 code_challenge;
第三步:客户端利用返回的 code 和 code_verifier 来向 oauth2 服务器申请 token;
第四步:客户端通过在 header 里加 bearer token 就能访问受限资源了;
可以参考相关的案例
参考文档
CodeChallengeMethod类用来codeVerifier和codeChallenge比较PkceAuthorizationCodeServices类用于调度PkceAuthorizationCodeTokenGranter类用于从request请求中获取token所需信息PkceProtectedAuthentication类定义PKCE认证对象信息
全局跨域访问和 Token 调用设置
参考网址:
一个受限的设备连接到网络时,不是直接对用户进行身份验证,设备会要求用户转到其计算机或智能手机上的链接并授权设备。这避免了无法轻松输入文本的设备的糟糕用户体验。为此,设备应用程序使用设备授权流程 (ratified in OAuth 2.0),在其中传递 Client ID 用来启动授权过程并获取 token。
设备授权流程包含两条不同的路径:一个发生在请求授权的设备上,另一个发生在浏览器中。浏览器路径,其中 device code 绑定到浏览器中的 session,与设备路径的一部分平行发生。
用户在设备上启动应用程序。
设备应用程序使用其 Client ID 从授权服务器请求授权(/oauth2/device/code 端点)。
授权服务器响应device_code
, user_code
, verification_uri
, verification_uri_complete
, expires_in
(device_code
和 user_code
的生命周期以秒为单位),和轮询间隔。
设备应用程序要求用户使用他们的计算机或智能手机进行激活。该应用程序可以通过以下方式完成此操作:
verify_uri
并输入 user_code
verify_uri_complete
生成的内嵌user code
与 二维码或短 URL 进行交互。verify_uri_complete
直接导航到带有user code
的验证页面。设备应用程序根据指定的时间间隔 interval
,开始轮询您的授权服务器以获取访问令牌(/oauth2/token 端点)。设备应用程序会继续轮询,直到用户完成浏览器上的确认操作或 user code 过期。
判断用户是否完成操作。在等待的过程。。。。。。
用户完成浏览器上的确认操作后,授权服务器返回 Access Token(以及可选的 Refresh Token),设备应用程序现在应该忘记它的 device_code,因为它会过期。
您的设备应用可以使用 Access Token 调用 API 以访问有关用户的信息。
API 返回请求的数据。
用户在其计算机上访问verify_uri
,输入 user_code
并确认正在激活的设备正在显示 user_code
。如果用户通过任何其他方法访问verification_uri_complete
(例如通过扫描二维码),只需要设备确认。
如果需要,授权服务器会将用户重定向到登录和同意提示。
用户使用配置的登录选项之一进行身份验证,并且可能会看到要求授权设备应用程序的同意页面。
您的设备应用程序已获得访问 API
的授权。
curl --request POST \--url 'https://YOUR_DOMAIN/oauth/device/code' \--header 'content-type: application/x-www-form-urlencoded' \--data 'client_id=YOUR_CLIENT_ID' \--data scope=SCOPE \--data audience=AUDIENCE
Device code response
{"device_code": "Ag_EE...ko1p","user_code": "QTZL-MCBW","verification_uri": "https://accounts.acmetest.org/activate","verification_uri_complete": "https://accounts.acmetest.org/activate?user_code=QTZL-MCBW","expires_in": 900,"interval": 5}
device_code 不直接用于用户,不应在交互过程中显示以避免混淆用户。
Once you received a device code
and use code
,可以在设备上显示这么一个提示
curl --request POST \--url 'https://YOUR_DOMAIN/oauth/token' \--header 'content-type: application/x-www-form-urlencoded' \--data grant_type=urn:ietf:params:oauth:grant-type:device_code \--data device_code=YOUR_DEVICE_CODE \--data 'client_id=YOUR_CLIENT_ID'
grant_type 将此设置为“urn:ietf:params:oauth:grant-type:device_code”。这是扩展授权类型(由 RFC6749 的第 4.5 节定义)请注意,这必须是 URL 编码的。
收到下面,就继续轮询
{"error": "authorization_pending","error_description": "..."}
放慢访问速度
{"error": "slow_down","error_description": "..."}
过期
{"error": "expired_token","error_description": "..."}
拒绝
{"error": "access_denied","error_description": "..."}
输入用户编号
确认设备
用户将通过登录完成交易。
当用户一直在对设备进行身份验证和授权时,设备应用程序会继续轮询令牌 URL 以请求访问令牌。
{"access_token": "eyJz93a...k4laUWw","refresh_token": "GEbRxBN...edjnXbL","id_token": "eyJ0XAi...4faeEoQ","token_type": "Bearer","expires_in": 86400}