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 或友好名称格式。 然而,此参数不能设置为 common 或 consumers ,但可以设置为 organizations 。 |
client_id |
必须 | Microsoft Entra 管理中心 - 应用注册页分配给应用的“应用程序(客户端) ID”。 |
grant_type |
必须 | 必须设置为 password 。 |
username |
必选 | 用户的电子邮件地址。 |
password |
必选 | 用户的密码。 |
scope |
建议 | 以空格分隔的范围或权限的列表,这是应用需要的。 在交互式流中,管理员或用户必须提前同意这些作用域。 |
client_secret |
有时必需 | 如果你的应用是公用客户端,则不能包含 client_secret 或 client_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 控制台应用程序代码示例。