Microsoft 标识平台和 OAuth 2.0 资源所有者密码凭据

Microsoft 标识平台支持 OAuth 2.0 资源所有者密码凭据 (ROPC) 授权,后者允许应用程序通过直接处理用户的密码来登录用户。 本文介绍如何在应用程序中直接针对协议进行编程。 如果可能,建议你改用受支持的 Microsoft 身份验证库 (MSAL) 来获取令牌并调用受保护的 Web API。 另请参阅使用 MSAL 的示例应用

警告

Microsoft 建议不要使用 ROPC 流。 在大多数情况下,可以使用我们建议的更安全的替代方案。 在应用程序中,此流需要非常高的信任度,并携带其他流中不存在的风险。 仅当不能使用其他更安全的流时,才应使用此流。

重要

  • Microsoft 标识平台仅支持 Microsoft Entra 租户内的 ROPC 授权。 这意味着,必须使用特定于租户的终结点 (https://login.partner.microsoftonline.cn/{TenantId_or_Name}) 或 organizations 终结点。
  • 没有密码的帐户无法使用 ROPC 登录,这意味着 SMS 登录、FIDO 等功能以及 Authenticator 应用都不可用于该流。 如果应用或用户需要这些功能,请使用 ROPC 以外的授权类型。
  • 如果用户需使用多重身份验证 (MFA) 来登录应用程序,则系统会改为阻止用户。
  • 混合标识联合身份验证方案(例如,用于对本地帐户进行身份验证的 Microsoft Entra ID 和 ADFS)不支持 ROPC。 如果用户被整页重定向到本地标识提供者,则 Microsoft Entra ID 无法针对该标识提供者测试用户名和密码。
  • 混合联合身份身份验证方案的一种例外情况如下:当本地密码同步到云时,将 AllowCloudPasswordValidation 设置为 TRUE 时,Home Realm Discovery 策略将启用 ROPC 流来处理联合用户。 有关详细信息,请参阅为旧版应用程序启用对联合用户的直接 ROPC 身份验证
  • ROPC 流程不支持带有前导或尾随空格的密码。

协议图

下图显示了 ROPC 流。

显示资源所有者密码凭据流的关系图

授权请求

ROPC 流是单一请求;它将客户端标识和用户凭据发送到标识提供者,并接收返回的令牌。 在这样做之前,客户端必须请求用户的电子邮件地址 (UPN) 和密码。 在成功进行请求之后,客户端应立即以安全方式放弃内存中的用户凭据。 客户端不得保存客户凭据。

// Line breaks and spaces are for legibility only.  This is a public client, so no secret is required.

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

client_id=00001111-aaaa-2222-bbbb-3333cccc4444
&scope=user.read%20openid%20profile%20offline_access
&username=MyUsername@myTenant.com
&password=SuperS3cret
&grant_type=password
参数 条件 描述
tenant 必选 一个目录租户,用户需登录到其中。 租户可采用 GUID 或友好名称格式。 然而,此参数不能设置为 commonconsumers,但可以设置为 organizations
client_id 必须 Microsoft Entra 管理中心 - 应用注册页分配给应用的“应用程序(客户端) ID”。
grant_type 必须 必须设置为 password
username 必选 用户的电子邮件地址。
password 必选 用户的密码。
scope 建议 以空格分隔的范围或权限的列表,这是应用需要的。 在交互式流中,管理员或用户必须提前同意这些作用域。
client_secret 有时必需 如果你的应用是公用客户端,则不能包含 client_secretclient_assertion。 如果应用是机密客户端,则它必须包括在内。
client_assertion 有时必需 使用证书生成的不同形式的 client_secret。 有关详细信息,请参阅证书凭据

成功的身份验证响应

以下示例显示了一个成功的令牌响应:

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

可以运行 OAuth 代码流文档中描述的同一个流,使用刷新令牌来获取新的访问令牌和刷新令牌。

警告

请勿尝试在代码中验证或读取你未拥有的任何 API 的令牌,包括此示例中的令牌。 Microsoft 服务的令牌可以使用将不会作为 JWT 进行验证的特殊格式,还可能会针对使用者(Microsoft 帐户)用户进行加密。 虽然可以通过读取令牌的操作进行调试和学习,但请不要在代码中依赖此操作,也不要假定不是你控制的 API 的令牌的相关具体信息。

错误响应

如果用户未提供正确的用户名或密码,或者客户端未收到请求的许可,则身份验证会失败。

错误 说明 客户端操作
invalid_grant 身份验证失败 凭据不正确,或者客户端没有所请求范围的许可。 如果没有授予范围,则会返回 consent_required 错误。 若要解决此错误,客户端应通过 Webview 或浏览器向用户发送交互式提示。
invalid_request 请求的构造方式不正确 授予类型在 /common/consumers 身份验证上下文中不受支持。 请改用 /organizations 或租户 ID。

了解详细信息

有关 ROPC 流的示例实现,请参阅 GitHub 上的 .NET 控制台应用程序代码示例。