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 或友好名称格式。 但是,其参数不能设置为 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 |
字符串 | 始终将其设置为 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 控制台应用程序 代码示例。