Microsoft 标识平台和隐式授权流Microsoft identity platform and implicit grant flow

Microsoft 标识平台支持 OAuth 2.0 规范中所述的 OAuth 2.0 隐式授权流。The Microsoft identity platform supports the OAuth 2.0 Implicit Grant flow as described in the OAuth 2.0 Specification. 隐式授权的定义特征是令牌(ID 令牌或访问令牌)直接从 /authorize 终结点返回,而不是从 /token 终结点返回。The defining characteristic of the implicit grant is that tokens (ID tokens or access tokens) are returned directly from the /authorize endpoint instead of the /token endpoint. 这通常在所谓的“混合流”中用作授权代码流的一部分 - 在 /authorize 请求中检索 ID 令牌以及授权代码。This is often used as part of the authorization code flow, in what is called the "hybrid flow" - retrieving the ID token on the /authorize request along with an authorization code.

本文介绍如何直接针对应用程序中的协议进行编程,以从 Azure AD 请求令牌。This article describes how to program directly against the protocol in your application to request tokens from Azure AD. 如果可能,建议你改用受支持的 Microsoft 身份验证库 (MSAL) 来获取令牌并调用受保护的 Web APIWhen possible, we recommend you use the supported Microsoft Authentication Libraries (MSAL) instead to acquire tokens and call secured web APIs. 另请参阅使用 MSAL 的示例应用Also take a look at the sample apps that use MSAL.

首选授权代码流Prefer the auth code flow

由于计划从浏览器中删除第三方 Cookie,因此,隐式授权流不再是合适的身份验证方法。With the plans for third party cookies to be removed from browsers, the implicit grant flow is no longer a suitable authentication method. 如果没有第三方 Cookie,隐式流的无提示 SSO 功能将不起作用,导致应用程序在尝试获取新令牌时中断。The silent SSO features of the implicit flow do not work without third party cookies, causing applications to break when they attempt to get a new token. 强烈建议你让所有新的应用程序都使用授权代码流(现在替代隐式流来支持单页应用),并让现有的单页应用也开始迁移到授权代码流We strongly recommend that all new applications use the authorization code flow that now supports single page apps in place of the implicit flow, and that existing single page apps begin migrating to the authorization code flow as well.

OAuth2 隐式授权的适用方案Suitable scenarios for the OAuth2 implicit grant

只有对于登录流的初始交互式部分(其中缺少第三方 Cookie 不会影响你的应用程序),隐式授权才是可靠的。The implicit grant is only reliable for the initial, interactive portion of your sign in flow, where the lack of third party cookies cannot impact your application. 此限制意味着,你只应将其用作混合流的一部分,在混合流中,你的应用程序从授权终结点请求代码和令牌。This limitation means you should use it exclusively as part of the hybrid flow, where your application requests a code as well as a token from the authorization endpoint. 这可确保应用程序收到可兑换为刷新令牌的代码,从而确保应用的登录会话在一段时间内保持有效。This ensures that your application receives a code that can be redeemed for a refresh token, thus ensuring your app's login session remains valid over time.

协议图Protocol diagram

下图显示了整个隐式登录流的样子,后续各部分更详细地介绍了每个步骤。The following diagram shows what the entire implicit sign-in flow looks like and the sections that follow describe each step in more detail.

显示隐式登录流的关系图

发送登录请求Send the sign-in request

最初将用户登录到应用时,可以发送 OpenID Connect 身份验证请求,并从 Microsoft 标识平台终结点获取 id_tokenTo initially sign the user into your app, you can send an OpenID Connect authentication request and get an id_token from the Microsoft identity platform endpoint.

重要

若要成功请求 ID 令牌和/或访问令牌,必须通过在“隐式授权”部分下选择“ID 令牌”和/或“访问令牌”,为 Azure 门户 - 应用注册页中的应用注册启用相应的隐式授权流。 To successfully request an ID token and/or an access token, the app registration in the Azure portal - App registrations page must have the corresponding implicit grant flow enabled, by selecting ID tokens and.or access tokens under the Implicit grant section. 如果未启用,将返回 unsupported_response 错误:为输入参数“response_type”提供的值不允许用于此客户端。预期值为“code””If it's not enabled, an unsupported_response error will be returned: The provided value for the input parameter 'response_type' is not allowed for this client. Expected value is 'code'

// Line breaks for legibility only

https://login.partner.microsoftonline.cn/{tenant}/oauth2/v2.0/authorize?
client_id=6731de76-14a6-49ae-97bc-6eba6914391e
&response_type=id_token
&redirect_uri=http%3A%2F%2Flocalhost%2Fmyapp%2F
&scope=openid
&response_mode=fragment
&state=12345
&nonce=678910

提示

若要使用隐式流测试登录,请单击 https://login.partner.microsoftonline.cn/common/oauth2/v2.0/authorize..在登录之后,浏览器应重定向到 https://localhost/myapp/ ,并且地址栏中有一个 id_tokenTo test signing in using the implicit flow, click https://login.partner.microsoftonline.cn/common/oauth2/v2.0/authorize... After signing in, your browser should be redirected to https://localhost/myapp/ with an id_token in the address bar.

参数Parameter 类型Type 说明Description
tenant 必需required 请求路径中的 {tenant} 值可用于控制哪些用户可以登录应用程序。The {tenant} value in the path of the request can be used to control who can sign into the application. 可以使用的值包括 commonorganizationsconsumers 和租户标识符。The allowed values are common, organizations, consumers, and tenant identifiers. 有关详细信息,请参阅协议基础知识For more detail, see protocol basics.
client_id 必需required Azure 门户 - 应用注册页分配给应用的应用程序(客户端)ID。The Application (client) ID that the Azure portal - App registrations page assigned to your app.
response_type 必填required 必须包含 OpenID Connect 登录的 id_tokenMust include id_token for OpenID Connect sign-in. 也可以包含 response_type tokenIt may also include the response_type token. 此处使用 token ,让应用能够立即从授权终结点接收访问令牌,而无需向授权终结点发出第二次请求。Using token here will allow your app to receive an access token immediately from the authorize endpoint without having to make a second request to the authorize endpoint. 如果使用 token response_type,scope 参数必须包含范围,以指出要对哪个资源(例如,Microsoft Graph 上的 user.read)发出令牌。If you use the token response_type, the scope parameter must contain a scope indicating which resource to issue the token for (for example, user.read on Microsoft Graph). 它还可以包含可提供授权代码的 code(取代 token),该授权代码在授权代码流中使用。It can also contain code in place of token to provide an authorization code, for use in the authorization code flow. 此“id_token+代码”响应有时称为混合流。This id_token+code response is sometimes called the hybrid flow.
redirect_uri 建议recommended 应用的 redirect_uri,应用可向其发送及从其接收身份验证响应。The redirect_uri of your app, where authentication responses can be sent and received by your app. 它必须完全符合在门户中注册的其中一个 redirect_uris,否则必须是编码的 url。It must exactly match one of the redirect_uris you registered in the portal, except it must be url encoded.
scope 必填required 范围的空格分隔列表。A space-separated list of scopes. 对于 OpenID Connect (id_token),它必须包含范围 openid,该范围在许可 UI 中会转换为“将你登录”权限。For OpenID Connect (id_tokens), it must include the scope openid, which translates to the "Sign you in" permission in the consent UI. 或者,也可以包含 emailprofile 范围,以获取对其他用户数据的访问权限。Optionally you may also want to include the email and profile scopes for gaining access to additional user data. 也可以在此请求中包含其他范围,以请求对各种资源的许可(如果请求了访问令牌)。You may also include other scopes in this request for requesting consent to various resources, if an access token is requested.
response_mode 可选optional 指定将生成的令牌送回到应用程序时应该使用的方法。Specifies the method that should be used to send the resulting token back to your app. 默认为仅查询访问令牌,但如果请求包括 id_token,则会进行分段。Defaults to query for just an access token, but fragment if the request includes an id_token.
state 建议recommended 同样随令牌响应返回的请求中所包含的值。A value included in the request that will also be returned in the token response. 可以是想要的任何内容的字符串。It can be a string of any content that you wish. 随机生成的唯一值通常用于 防止跨站点请求伪造攻击A randomly generated unique value is typically used for preventing cross-site request forgery attacks. 该 state 也用于在身份验证请求出现之前,于应用中编码用户的状态信息,例如之前所在的网页或视图。The state is also used to encode information about the user's state in the app before the authentication request occurred, such as the page or view they were on.
nonce 必填required 包含在请求中的值,由应用生成,这些值将作为声明包含在生成的 id_token 中。A value included in the request, generated by the app, that will be included in the resulting id_token as a claim. 然后,应用可以验证此值,以减少令牌重播攻击。The app can then verify this value to mitigate token replay attacks. 该值通常是随机的唯一字符串,可用于标识请求的来源。The value is typically a randomized, unique string that can be used to identify the origin of the request. 只有请求 id_token 时才是必需的。Only required when an id_token is requested.
prompt 可选optional 表示需要的用户交互类型。Indicates the type of user interaction that is required. 目前的有效值为“login”、“none”、“select_account”和“consent”。The only valid values at this time are 'login', 'none', 'select_account', and 'consent'. prompt=login 将强制用户在该请求上输入凭据,取消单一登录。prompt=login will force the user to enter their credentials on that request, negating single-sign on. prompt=none 则相反 - 它确保不对用户显示任何交互式提示。prompt=none is the opposite - it will ensure that the user isn't presented with any interactive prompt whatsoever. 如果请求无法通过单一登录静默完成,则 Microsoft 标识平台终结点将返回一个错误。If the request can't be completed silently via single-sign on, the Microsoft identity platform endpoint will return an error. prompt=select_account 将用户发送到一个帐户选取器,其中将显示在会话中记住的所有帐户。prompt=select_account sends the user to an account picker where all of the accounts remembered in the session will appear. prompt=consent 会在用户登录之后触发 OAuth 同意对话框,要求用户向应用授予权限。prompt=consent will trigger the OAuth consent dialog after the user signs in, asking the user to grant permissions to the app.
login_hint 可选optional 如果事先知道用户的用户名,可用于预先填充用户登录页面的用户名/电子邮件地址字段。Can be used to pre-fill the username/email address field of the sign in page for the user, if you know their username ahead of time. 通常,应用会在重新进行身份验证期间使用此参数,并且已经使用 preferred_username 声明从前次登录提取用户名。Often apps will use this parameter during reauthentication, having already extracted the username from a previous sign-in using the preferred_username claim.
domain_hint 可选optional 如果包含,它跳过用户在登录页上经历的基于电子邮件的发现过程,导致稍微更加流畅的用户体验。If included, it will skip the email-based discovery process that user goes through on the sign in page, leading to a slightly more streamlined user experience. 此参数通常用于在单个租户中运行的业务线应用,它们会提供给定租户中的域名,将用户转发给该租户的联合身份验证提供程序。This parameter is commonly used for Line of Business apps that operate in a single tenant, where they will provide a domain name within a given tenant, forwarding the user to the federation provider for that tenant. 请注意,此提示会阻止来宾登录到此应用程序,并限制 FIDO 之类的云凭据的使用。Note that this hint prevents guests from signing into this application, and limits the use of cloud credentials like FIDO.

此时,将请求用户输入凭据并完成身份验证。At this point, the user will be asked to enter their credentials and complete the authentication. Microsoft 标识平台终结点还会确保用户已许可 scope 查询参数中指定的权限。The Microsoft identity platform endpoint will also ensure that the user has consented to the permissions indicated in the scope query parameter. 如果用户未曾同意这些权限的任何一项,就请求用户同意请求的权限。If the user has consented to none of those permissions, it will ask the user to consent to the required permissions. 有关详细信息,请参阅权限、同意和多租户应用For more info, see permissions, consent, and multi-tenant apps.

用户经过身份验证并授予许可后,Microsoft 标识平台终结点将使用 response_mode 参数中指定的方法,将响应返回到位于所指示的 redirect_uri 的应用。Once the user authenticates and grants consent, the Microsoft identity platform endpoint will return a response to your app at the indicated redirect_uri, using the method specified in the response_mode parameter.

成功的响应Successful response

使用 response_mode=fragmentresponse_type=id_token+code 的成功响应如下所示(为方便阅读,包含了换行符):A successful response using response_mode=fragment and response_type=id_token+code looks like the following (with line breaks for legibility):

GET https://localhost/myapp/#
code=0.AgAAktYV-sfpYESnQynylW_UKZmH-C9y_G1A
&id_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ik5HVEZ2ZEstZnl0aEV1Q...
&state=12345
参数Parameter 说明Description
code 如果 response_type 包含 code,则包含该参数。Included if response_type includes code. 这是适合在授权代码流中使用的授权代码。This is an authorization code suitable for use in the authorization code flow.
access_token 如果 response_type 包含 token,则包含该参数。Included if response_type includes token. 应用请求的访问令牌。The access token that the app requested. 访问令牌不得进行解码或检查,应当作为不透明字符串对待。The access token shouldn't be decoded or otherwise inspected, it should be treated as an opaque string.
token_type 如果 response_type 包含 token,则包含该参数。Included if response_type includes token. 始终为 BearerWill always be Bearer.
expires_in 如果 response_type 包含 token,则包含该参数。Included if response_type includes token. 表示令牌有效的秒数(针对缓存目的)。Indicates the number of seconds the token is valid, for caching purposes.
scope 如果 response_type 包含 token,则包含该参数。Included if response_type includes token. 表示 access_token 的有效范围。Indicates the scope(s) for which the access_token will be valid. 可能不包括所有请求的范围(如果它们不适用于用户)。May not include all of the scopes requested, if they were not applicable to the user.
id_token 有符号 JSON Web 令牌 (JWT)。A signed JSON Web Token (JWT). 应用可以解码此令牌的段,以请求已登录用户的相关信息。The app can decode the segments of this token to request information about the user who signed in. 应用可以缓存并显示值,但不应依赖于这些值来获取任何授权或安全边界。The app can cache the values and display them, but it shouldn't rely on them for any authorization or security boundaries. 有关 id_tokens 的详细信息,请参阅 id_token referenceFor more information about id_tokens, see the id_token reference.
注意: 仅当请求了 openid 作用域且 response_type 包括 id_tokens 时才提供。Note: Only provided if openid scope was requested and response_type included id_tokens.
state 如果请求中包含 state 参数,响应中就应该出现相同的值。If a state parameter is included in the request, the same value should appear in the response. 应用应该验证请求和响应中的 state 值是否完全相同。The app should verify that the state values in the request and response are identical.

错误响应Error response

错误响应可能也发送到 redirect_uri ,让应用可以适当地处理:Error responses may also be sent to the redirect_uri so the app can handle them appropriately:

GET https://localhost/myapp/#
error=access_denied
&error_description=the+user+canceled+the+authentication
参数Parameter 说明Description
error 可用于分类发生的错误类型与响应错误的错误码字符串。An error code string that can be used to classify types of errors that occur, and can be used to react to errors.
error_description 帮助开发人员识别身份验证错误根本原因的特定错误消息。A specific error message that can help a developer identify the root cause of an authentication error.

在后台以无提示方式获取访问令牌Getting access tokens silently in the background

重要

隐式流的这一部分不太可能适用于你的应用程序,因为默认情况下删除了第三方 Cookie,所以它用于各种浏览器中。This part of the implicit flow is unlikely to work for your application as it's used across different browsers due to the removal of third party cookies by default. 虽然目前这仍然适用于不在 Incognito 中的基于 Chromium 的浏览器,但开发人员应该重新考虑这部分流的使用。While this still currently works in Chromium-based browsers that are not in Incognito, developers should reconsider using this part of the flow. 在不支持第三方 Cookie 的浏览器中,你会收到一条错误消息,指出没有用户登录,因为浏览器删除了登录页面的会话 Cookie。In browsers that do not support third party cookies, you will recieve an error indicating that no users are signed in, as the login page's session cookies were removed by the browser.

已经将用户登录到单页应用,现在可以通过无提示方式获取访问令牌以调用受到 Microsoft 标识平台保护的 Web API,例如 Microsoft GraphNow that you've signed the user into your single-page app, you can silently get access tokens for calling web APIs secured by Microsoft identity platform, such as the Microsoft Graph. 即使已使用 token response_type 收到令牌,仍然可以使用此方法获取其他资源的令牌,而无需再次将用户重定向到登录页。Even if you already received a token using the token response_type, you can use this method to acquire tokens to additional resources without having to redirect the user to sign in again.

在正常的 OpenID Connect/OAuth 流中,可以通过对 Microsoft 标识平台 /token 终结点进行请求来实现此目的。In the normal OpenID Connect/OAuth flow, you would do this by making a request to the Microsoft identity platform /token endpoint. 你可以在隐藏的 iframe 中进行请求,以获取其他 Web API 的新令牌:You can make the request in a hidden iframe to get new tokens for other web APIs:

// Line breaks for legibility only

https://login.partner.microsoftonline.cn/{tenant}/oauth2/v2.0/authorize?
client_id=6731de76-14a6-49ae-97bc-6eba6914391e
&response_type=token
&redirect_uri=http%3A%2F%2Flocalhost%2Fmyapp%2F
&scope=https%3A%2F%2Fmicrosoftgraph.chinacloudapi.cn%2Fuser.read
&response_mode=fragment
&state=12345
&nonce=678910
&prompt=none
&login_hint=myuser@mycompany.com

有关 URL 中的查询参数的详细信息,请参阅发送登录请求For details on the query parameters in the URL, see send the sign in request.

提示

请尝试将以下请求复制并粘贴到浏览器选项卡中!Try copy & pasting the below request into a browser tab! (不要忘记使用适用于用户的正确值替换 login_hint 值)(Don't forget to replace the login_hint values with the correct value for your user)

https://login.partner.microsoftonline.cn/common/oauth2/v2.0/authorize?client_id=6731de76-14a6-49ae-97bc-6eba6914391e&response_type=token&redirect_uri=http%3A%2F%2Flocalhost%2Fmyapp%2F&scope=https%3A%2F%2Fmicrosoftgraph.chinacloudapi.cn%2Fuser.read&response_mode=fragment&state=12345&nonce=678910&prompt=none&login_hint={your-username}

请注意,即使是在不支持第三方 Cookie 的浏览器中,也可以这样做,因为你要将其直接输入到浏览器栏中,而不是在 iframe 中打开它。Note that this will work even in browsers without third party cookie support, since you're entering this directly into a browser bar as opposed to opening it within an iframe.

借助 prompt=none 参数,此请求立即成功或立即失败,并返回应用程序。Thanks to the prompt=none parameter, this request will either succeed or fail immediately and return to your application. 响应会通过 response_mode 参数中指定的方法,发送到位于所指示的 redirect_uri 的应用。The response will be sent to your app at the indicated redirect_uri, using the method specified in the response_mode parameter.

成功的响应Successful response

使用 response_mode=fragment 的成功响应如下所示:A successful response using response_mode=fragment looks like:

GET https://localhost/myapp/#
access_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ik5HVEZ2ZEstZnl0aEV1Q...
&state=12345
&token_type=Bearer
&expires_in=3599
&scope=https%3A%2F%2Fmicrosoftgraph.chinacloudapi.cn%2Fdirectory.read
参数Parameter 说明Description
access_token 如果 response_type 包含 token,则包含该参数。Included if response_type includes token. 应用请求的访问令牌,在本例中为 Microsoft Graph 的访问令牌。The access token that the app requested, in this case for the Microsoft Graph. 访问令牌不得进行解码或检查,应当作为不透明字符串对待。The access token shouldn't be decoded or otherwise inspected, it should be treated as an opaque string.
token_type 始终为 BearerWill always be Bearer.
expires_in 表示令牌有效的秒数(针对缓存目的)。Indicates the number of seconds the token is valid, for caching purposes.
scope 表示 access_token 的有效范围。Indicates the scope(s) for which the access_token will be valid. 可能不包括所有请求的范围(如果它们不适用于用户)。May not include all of the scopes requested, if they were not applicable to the user.
id_token 有符号 JSON Web 令牌 (JWT)。A signed JSON Web Token (JWT). 如果 response_type 包含 id_token,则包含该参数。Included if response_type includes id_token. 应用可以解码此令牌的段,以请求已登录用户的相关信息。The app can decode the segments of this token to request information about the user who signed in. 应用可以缓存并显示值,但不应依赖于这些值来获取任何授权或安全边界。The app can cache the values and display them, but it shouldn't rely on them for any authorization or security boundaries. 有关 id_tokens 的详细信息,请参阅id_token参考For more information about id_tokens, see the id_token reference.
注意: 仅当已请求 openid 作用域时提供。Note: Only provided if openid scope was requested.
state 如果请求中包含 state 参数,响应中就应该出现相同的值。If a state parameter is included in the request, the same value should appear in the response. 应用应该验证请求和响应中的 state 值是否完全相同。The app should verify that the state values in the request and response are identical.

错误响应Error response

错误响应还可能发送到 redirect_uri ,因此应用可以适当地对其进行处理。Error responses may also be sent to the redirect_uri so the app can handle them appropriately. 如果是 prompt=none,预期的错误为:In the case of prompt=none, an expected error will be:

GET https://localhost/myapp/#
error=user_authentication_required
&error_description=the+request+could+not+be+completed+silently
参数Parameter 说明Description
error 可用于分类发生的错误类型与响应错误的错误码字符串。An error code string that can be used to classify types of errors that occur, and can be used to react to errors.
error_description 帮助开发人员识别身份验证错误根本原因的特定错误消息。A specific error message that can help a developer identify the root cause of an authentication error.

如果在 iframe 请求中收到此错误,用户必须再次以交互方式登录以检索新令牌。If you receive this error in the iframe request, the user must interactively sign in again to retrieve a new token. 可以选择对应用程序合理的任何方式处理这种情况。You can choose to handle this case in whatever way makes sense for your application.

刷新令牌Refreshing tokens

隐式授权不提供刷新令牌。The implicit grant does not provide refresh tokens. id_tokenaccess_token 很快就会过期,因此应用必须准备好定期刷新这些令牌。Both id_tokens and access_tokens will expire after a short period of time, so your app must be prepared to refresh these tokens periodically. 若要刷新任一类型的令牌,可以通过使用 prompt=none 参数控制 Microsoft 标识平台的行为,来执行上述同一隐藏的 iframe 请求。To refresh either type of token, you can perform the same hidden iframe request from above using the prompt=none parameter to control the identity platform's behavior. 若要接收新的 id_token,请务必使用 response_typescope=openid 中的 id_token,以及 nonce 参数。If you want to receive a new id_token, be sure to use id_token in the response_type and scope=openid, as well as a nonce parameter.

在不支持第三方 Cookie 的浏览器中,这会导致错误,指出没有用户登录。In browsers that do not support third party cookies, this will result in an error indicating that no user is signed in.

发送注销请求Send a sign out request

OpenID Connect end_session_endpoint 允许应用向 Microsoft 标识平台终结点发送请求以结束用户的会话,并清除 Microsoft 标识平台终结点设置的 Cookie。The OpenID Connect end_session_endpoint allows your app to send a request to the Microsoft identity platform endpoint to end a user's session and clear cookies set by the Microsoft identity platform endpoint. 要完全将用户从 Web 应用程序注销,应用应结束自己与用户的会话(通常通过清除令牌缓存或删除 Cookie 实现),然后将浏览器重定向到:To fully sign a user out of a web application, your app should end its own session with the user (usually by clearing a token cache or dropping cookies), and then redirect the browser to:

https://login.partner.microsoftonline.cn/{tenant}/oauth2/v2.0/logout?post_logout_redirect_uri=https://localhost/myapp/
参数Parameter 类型Type 说明Description
tenant 必需required 请求路径中的 {tenant} 值可用于控制哪些用户可以登录应用程序。The {tenant} value in the path of the request can be used to control who can sign into the application. 可以使用的值包括 commonorganizationsconsumers 和租户标识符。The allowed values are common, organizations, consumers, and tenant identifiers. 有关详细信息,请参阅协议基础知识For more detail, see protocol basics.
post_logout_redirect_uri 建议recommended 注销完成后用户应返回到的 URL。The URL that the user should be returned to after logout completes. 此值必须与为应用程序注册的重定向 URI 之一匹配。This value must match one of the redirect URIs registered for the application. 如果未包含,Microsoft 标识平台终结点会向用户显示一条常规消息。If not included, the user will be shown a generic message by the Microsoft identity platform endpoint.

后续步骤Next steps