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

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

警告

Microsoft建议不要使用 ROPC 流;它与多重身份验证 (MFA) 不兼容。 在大多数情况下,提供了更安全的替代方法,建议使用。 此流需要在应用程序中高度信任,并且存在在其他流中不存在的风险。 仅当更安全的流不可行时,才应使用此流。

重要

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

如何从 ROPC 迁移

随着 MFA 变得更加普遍,一些Microsoft Web API 只有在通过 MFA 要求时才接受访问令牌。 依赖于 ROPC 的应用程序和测试钻机将被锁定。Microsoft Entra 不会颁发令牌,或者资源将拒绝请求。

如果使用 ROPC 获取令牌来调用受保护的下游 API,请迁移到安全令牌获取策略。

当用户上下文可用时

如果最终用户需要访问资源,则代表其作的客户端应用程序应使用交互式身份验证的形式。 最终用户只有在浏览器中出现 MFA 请求时,才会被要求进行验证。

  • 对于 Web 应用程序:
  • Web API 无法显示浏览器。 相反,它们必须将质询返回给客户端应用程序。 有关详细信息,请参阅 Web API在 Web API 中质询用户
  • 桌面应用程序应使用基于代理的身份验证。 代理使用基于浏览器的身份验证,因此它们可以强制实施 MFA,并尽可能启用最安全的状态。
  • 还应将移动应用程序配置为使用基于代理(Authenticator、公司门户)的身份验证。

当用户上下文不可用时

没有涉及用户上下文的情况包括但不限于以下示例:

  • 作为 CI 管道的一部分运行的脚本。
  • 服务需要代表自身调用资源,无需用户详细信息。

应用程序开发人员应使用 服务主体身份验证守护程序示例对此进行了说明。 MFA 不适用于服务主体。

可通过多种方式作为服务主体进行身份验证:

  • 如果应用在 Azure 基础结构上运行,请使用 托管标识。 托管标识消除了维护和轮换机密和证书的开销。
  • 如果应用在另一个符合 OAuth2 的标识提供者(如 GitHub)托管的系统上运行,请使用 联合标识凭据
  • 如果无法使用托管标识或联合标识,请使用证书凭据

警告

当用户上下文可用时,请勿使用服务主体身份验证。 仅应用访问权限本质上是高特权,通常授予租户范围的访问权限,并可能允许不良参与者访问任何用户的客户数据。

协议关系图

下图显示了 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.microsoftonline.com
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 字符串 始终将其设置为 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 错误。 若要解决此错误,客户端应使用 Web 视图或浏览器将用户发送到交互式提示。
invalid_request 请求构造不当 /common/consumers 身份验证上下文不支持授予类型。 请改用 /organizations 或租户 ID。

了解更多信息

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