Microsoft标识平台和 OAuth 2.0 设备授权授权流

Microsoft标识平台支持 设备授权,允许用户登录到受输入约束的设备,例如智能电视、IoT 设备或打印机。 若要启用此流,设备让用户在另一台设备上的浏览器中访问网页以登录。 用户登录后,设备能够根据需要获取访问令牌和刷新令牌。

本文介绍如何直接针对应用程序中的协议进行编程。 如果可能,建议改用受支持的Microsoft身份验证库(MSAL)来 获取令牌并调用受保护的 Web API。 可以参考 使用 MSAL 的示例应用

协议关系图

下图显示了整个设备代码流。 本文将介绍每个步骤。

设备代码流

设备授权请求

客户端必须首先检查用于启动身份验证的设备和用户代码的身份验证服务器。 客户端从 /devicecode 终结点收集此请求。 在请求中,客户端还应包含从用户获取所需的权限。

从发送请求的那一刻起,用户需要 15 分钟才能登录。 这是 expires_in的默认值。 仅当用户指示他们已准备好登录时,才应发出请求。

// Line breaks are for legibility only.

POST https://login.partner.microsoftonline.cn/{tenant}/oauth2/v2.0/devicecode
Content-Type: application/x-www-form-urlencoded

client_id=00001111-aaaa-2222-bbbb-3333cccc4444
&scope=user.read%20openid%20profile

参数 条件 DESCRIPTION
tenant 必选 可以是 /common 或 /organizations。 它也可以是想要从 GUID 或友好名称格式请求权限的目录租户。
client_id 必选 Microsoft Entra 管理中心 - 应用注册体验分配给应用的应用程序(客户端)ID
scope 必选 希望用户同意的范围的空格分隔列表。

设备授权响应

成功的响应是一个 JSON 对象,其中包含允许用户登录所需的信息。

参数 格式 DESCRIPTION
device_code 字符串 用于验证客户端和授权服务器之间的会话的长字符串。 客户端使用此参数来请求授权服务器提供访问令牌。
user_code 字符串 向用户显示的一个短字符串,用于标识辅助设备上的会话。
verification_uri URI 用户应转到 user_code 的 URI,以便登录。
expires_in 整数 (int) device_codeuser_code 过期之前的秒数。
interval 整数 (int) 客户端在轮询请求之间应等待的秒数。
message 字符串 用户可读的字符串,其中包含有关用户的说明。 这可以通过在表单请求中包含?mkt=xx-XX来本地化,并填写相应的语言区域性代码。

备注

此时 verification_uri_complete 不包含或支持响应字段。 我们提到这一点,因为如果你阅读标准,则会看到该verification_uri_complete作为设备代码流标准的可选部分列出。

对用户进行身份验证

客户端收到 user_codeverification_uri显示值后,系统会指示用户通过其移动或电脑浏览器登录。

当用户在身份验证时,客户端应使用 <a0/a0> 轮询请求的令牌的终结点。

POST https://login.partner.microsoftonline.cn/{tenant}/oauth2/v2.0/token
Content-Type: application/x-www-form-urlencoded

grant_type=urn:ietf:params:oauth:grant-type:device_code&client_id=00001111-aaaa-2222-bbbb-3333cccc4444&device_code=GMMhmHCXhWEzkobqIHGG_EnNYYsAkukHspeYUk9E8...
参数 必选 DESCRIPTION
tenant 必选 初始请求中使用的同一租户或租户别名。
grant_type 必选 必须是 urn:ietf:params:oauth:grant-type:device_code
client_id 必选 必须与初始请求中使用的匹配 client_id
device_code 必选 device_code设备授权请求中返回的。

预期错误

设备代码流是轮询协议,因此在完成用户身份验证之前,必须预期提供给客户端的错误。

错误 DESCRIPTION 客户行动
authorization_pending 用户尚未完成身份验证,但尚未取消流。 至少 interval 几秒钟后重复请求。
authorization_declined 最终用户拒绝了授权请求。 停止轮询并还原到未经身份验证的状态。
bad_verification_code device_code无法识别发送到/token终结点的终结点。 验证客户端是否在请求中发送正确的 device_code 值。
expired_token expires_in已超出该值,并且不再可以使用device_code身份验证。 停止轮询并还原到未经身份验证的状态。

身份验证响应成功

成功的令牌响应如下所示:

{
    "token_type": "Bearer",
    "scope": "User.Read profile openid email",
    "expires_in": 3599,
    "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ik5HVEZ2ZEstZnl0aEV1Q...",
    "refresh_token": "AwABAAAAvPM1KaPlrEqdFSBzjqfTGAMxZGUTdM0t4B4...",
    "id_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJhdWQiOiIyZDRkMTFhMi1mODE0LTQ2YTctOD..."
}
参数 格式 DESCRIPTION
token_type 字符串 始终为 Bearer
scope 空格分隔的字符串 如果返回了访问令牌,则会列出访问令牌的有效范围。
expires_in 整数 (int) 包含的访问令牌有效的秒数。
access_token 不透明字符串 针对请求的范围颁发。
id_token JWT 如果原始 scope 参数包含 openid 范围,则颁发。
refresh_token 不透明字符串 如果原始 scope 参数包含 offline_access,则颁发。

可以使用刷新令牌通过 OAuth 代码流文档中记录的相同流来获取新的访问令牌和刷新令牌。

警告

请勿尝试在代码中验证或读取您不拥有的任何 API 的令牌,包括本示例中的令牌。 Microsoft 服务的令牌可以使用将不会作为 JWT 进行验证的特殊格式,还可能会针对使用者(Microsoft 帐户)用户进行加密。 虽然读取令牌是一种有用的调试和学习工具,但不要在代码中依赖这一点,也不要对不属于你所控制API的令牌做出具体假设。