使用 OpenID Connect 和 Azure Active Directory 授权访问 Web 应用程序

警告

本内容适用于较旧版本的 Azure AD v1.0 终结点。 将 Microsoft标识平台 用于新项目。

OpenID Connect 是基于 OAuth 2.0 协议构建的简单标识层。 OAuth 2.0 定义了用于获取和使用 访问令牌 访问受保护资源的机制,但它们未定义提供标识信息的标准方法。 OpenID Connect 将身份验证作为 OAuth 2.0 授权过程的扩展实现。 它以 id_token 的形式提供有关最终用户的信息,用于验证用户的标识并提供有关用户的基本配置文件信息。

如果要构建托管在服务器上并通过浏览器访问的 Web 应用程序,则 OpenID Connect 是我们的建议。

将应用程序注册到您的 AD 租户

首先,将应用程序注册到 Azure Active Directory (Azure AD) 租户。 这将为你的应用程序提供一个应用程序 ID,并使它能够接收令牌。

  1. 登录到 Azure 门户

  2. 选择 Azure AD 租户,方法是在页面右上角选择帐户,然后选择 “切换目录 ”导航,然后选择相应的租户。

    • 如果帐户下只有一个 Azure AD 租户,或者已选择相应的 Azure AD 租户,请跳过此步骤。
  3. 在 Azure 门户中,搜索并选择 Azure Active Directory

  4. Azure Active Directory 左侧菜单中,选择 “应用注册”,然后选择“ 新建注册”。

  5. 按照提示进行操作并创建新应用程序。 本教程的 Web 应用程序或公共客户端(移动和桌面)应用程序并不重要,但如果想要 Web 应用程序或公共客户端应用程序的特定示例,请查看 我们的快速入门

    • 名称 是应用程序名称,并向最终用户描述应用程序。
    • 在“支持的帐户类型”下,选择“任何组织目录中的帐户和个人 Microsoft 帐户”。
    • 提供 重定向 URI。 对于 Web 应用程序,这是用户可以登录的应用的基本 URL。 例如,http://localhost:12345。 对于公共客户端(移动 & 桌面),Azure AD 使用它返回令牌响应。 输入特定于应用程序的值。 例如,http://MyFirstAADApp
  6. 完成注册后,Azure AD 将为应用程序分配唯一的客户端标识符( 应用程序 ID)。 在下一部分中需要此值,因此请从应用程序页复制此值。

  7. 若要在 Azure 门户中查找应用程序,请选择 “应用注册”,然后选择“ 查看所有应用程序”。

使用 OpenID Connect 的身份验证流

最基本的登录流包含以下步骤 - 下面详细介绍了每个登录流。

OpenId Connect 身份验证流

OpenID Connect 元数据文档

OpenID Connect 描述一个元数据文档,其中包含应用执行登录所需的大部分信息。 这包括要使用的 URL 和服务公共签名密钥的位置等信息。 可在以下位置找到 OpenID Connect 元数据文档:

https://login.microsoftonline.com/{tenant}/.well-known/openid-configuration

元数据是一个简单的 JavaScript 对象表示法(JSON)文档。 有关示例,请参阅以下代码片段。 此代码片段的内容在 openID Connect 规范 中完全描述。 请注意,提供租户 ID 而不是 common 代替上述 {tenant} 将导致返回 JSON 对象中特定于租户的 URI。

{
    "authorization_endpoint": "https://login.microsoftonline.com/{tenant}/oauth2/authorize",
    "token_endpoint": "https://login.microsoftonline.com/{tenant}/oauth2/token",
    "token_endpoint_auth_methods_supported":
    [
        "client_secret_post",
        "private_key_jwt",
        "client_secret_basic"
    ],
    "jwks_uri": "https://login.microsoftonline.com/common/discovery/keys"
    "userinfo_endpoint":"https://login.microsoftonline.com/{tenant}/openid/userinfo",
    ...
}

如果应用由于使用 声明映射 功能而具有自定义签名密钥,则必须追加包含 appid 应用 ID 的查询参数,才能获取 jwks_uri 指向应用的签名密钥信息。 例如:https://login.microsoftonline.com/{tenant}/.well-known/openid-configuration?appid=6731de76-14a6-49ae-97bc-6eba6914391e 包含 jwks_urihttps://login.microsoftonline.com/{tenant}/discovery/keys?appid=6731de76-14a6-49ae-97bc-6eba6914391e

发送登录请求

当 Web 应用程序需要对用户进行身份验证时,它必须将用户定向到 /authorize 终结点。 此请求类似于 OAuth 2.0 授权代码流的第一回合,但有一些重要的区别:

  • 请求必须在 openid 参数中包含范围 scope
  • response_type 参数必须包含 id_token
  • 请求必须包含 nonce 参数。

因此,示例请求如下所示:

// Line breaks for legibility only

GET https://login.microsoftonline.com/{tenant}/oauth2/authorize?
client_id=6731de76-14a6-49ae-97bc-6eba6914391e
&response_type=id_token
&redirect_uri=http%3A%2F%2Flocalhost%3a12345
&response_mode=form_post
&scope=openid
&state=12345
&nonce=7362CAEA-9CA5-4B43-9BA3-34D7C303EBA7
参数 类型 说明
租户 必填 请求路径中的 {tenant} 值可用于控制登录应用程序的用户。 允许的值是租户标识符,例如,用于租户无关令牌的 8eaef023-2b34-4da1-9baa-8bc8c9d6a490contoso.onmicrosoft.comcommon
客户端ID 必填 您在注册应用程序到 Azure AD 时所分配的应用程序 ID。 可以在 Azure 门户中找到此信息。 单击 Azure Active Directory,单击 “应用注册”,选择应用程序并在应用程序页上找到应用程序 ID。
response_type(响应类型) 必填 必须包含用于 OpenID Connect 登录的 id_token。 它还可能包括其他response_types,如 codetoken
范围 推荐 OpenID Connect 规范要求范围 openid,该范围转换为许可 UI 中的“登录”权限。 在 v1.0 终结点上,此 OIDC 范围和其他范围被忽略,但对于符合标准的客户端来说,仍然是最佳实践。
nonce 必填 由应用生成且包含在请求中的值,以声明方式包含在生成的 id_token 中。 然后,应用可以验证此值,以减少令牌重播攻击。 该值通常是随机的、唯一的字符串或 GUID,可用于标识请求的源。
重定向URI 推荐 您的应用程序的 redirect_uri,应用程序可在此处发送和接收身份验证响应。 它必须与您在门户中注册的某个 redirect_uris 完全匹配,但 URL 必须进行编码。 如果缺失,用户代理将被随机发回至应用注册的某个重定向 URI。 最大长度为 255 字节
响应模式 自选 指定用于将生成的授权代码发送回应用程序的方法。 支持的值适用于 form_postHTTP 表单帖子fragmentURL 片段。 对于 Web 应用程序,我们建议使用 response_mode=form_post 来确保将令牌安全传输到应用程序。 包含id_token的任何流的默认值为 fragment
推荐 请求中包含的一个值,随令牌响应返回。 任何你想要的内容都可以成为一个字符串。 随机生成的唯一值通常用于 防止跨站点请求伪造攻击。 该状态也用于在身份验证请求出现之前,对应用中用户的状态信息进行编码,例如用户之前浏览的网页或视图。
提示 自选 表示需要的用户交互类型。 目前,唯一有效的值为“login”、“none”和“consent”。 prompt=login 强制用户在该请求上输入其凭据,从而否定单一登录。 prompt=none 相反 - 它可确保用户不会显示任何交互式提示。 如果无法通过单一登录以无提示方式完成请求,终结点将返回错误。 prompt=consent 在用户登录后触发 OAuth 同意对话框,要求用户向应用授予权限。
登录提示 自选 如果您提前知道用户的用户名,可以用于预先填充登录页面的用户名或电子邮件地址字段。 通常,应用在重新身份验证期间使用此参数,并且已使用 preferred_username 声明从以前的登录中提取用户名。

此时,系统会要求用户输入凭据并完成身份验证。

示例响应

在用户进行身份验证后,发送到登录请求中指定的 redirect_uri 的示例响应可能如下所示:

POST / HTTP/1.1
Host: localhost:12345
Content-Type: application/x-www-form-urlencoded

id_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ik1uQ19WWmNB...&state=12345
参数 说明
id_token(身份令牌) 应用请求的 id_token。 可以使用 id_token 来验证用户的标识,并开始与用户进行会话。
请求中包含的一个值,也在令牌响应中返回。 随机生成的唯一值通常用于 防止跨站点请求伪造攻击。 该状态也用于在身份验证请求出现之前,对应用中用户的状态信息进行编码,例如用户之前浏览的网页或视图。

错误响应

错误响应可能也发送到 redirect_uri ,让应用可以适当地处理:

POST / HTTP/1.1
Host: localhost:12345
Content-Type: application/x-www-form-urlencoded

error=access_denied&error_description=the+user+canceled+the+authentication
参数 说明
错误 可用于分类错误类型并响应错误的错误码字符串。
错误描述 帮助开发人员识别身份验证错误根本原因的特定错误消息。

授权终结点错误的错误代码

下表描述了可在错误响应的 error 参数中返回的各个错误代码。

错误代码 说明 客户行动
无效请求 协议错误,例如,缺少必需的参数。 修复并重新提交请求。 这是一个开发错误,通常在初步测试时发现。
未授权的客户端 不允许客户端应用程序请求授权代码。 当客户端应用程序未在 Azure AD 中注册或未添加到用户的 Azure AD 租户时,通常会发生这种情况。 应用程序可以通过提供安装说明来提示用户进行应用程序的安装,并将其添加到 Azure AD。
拒绝访问 资源所有者拒绝了许可 除非用户同意,否则客户端应用程序可以通知用户无法继续。
不支持的响应类型 授权服务器不支持请求中的响应类型。 修复并重新提交请求。 这是一个开发错误,通常在初步测试时发现。
服务器错误 服务器遇到意外的错误。 重试请求。 这些错误可能是临时状况导致的。 客户端应用程序可能会向用户解释其响应因临时错误而延迟。
暂时不可用 服务器暂时繁忙,无法处理请求。 重试请求。 客户端应用程序可能会向用户解释,其响应因临时条件而延迟。
资源无效 目标资源无效,因为它不存在,Azure AD 找不到它,或者未正确配置。 这表示资源(如果存在)尚未在租户中配置。 应用程序可以通过提供安装说明来提示用户进行应用程序的安装,并将其添加到 Azure AD。

验证 id_token

仅接收 id_token 不足以对用户进行身份验证;必须根据应用的要求验证签名并验证 id_token 中的声明。 Azure AD 终结点使用 JSON Web 令牌(JWT)和公钥加密来对令牌进行签名并验证它们是否有效。

可以选择在客户端代码中验证 id_token,但一种常见做法是将 id_token 发送到后端服务器并在那里执行验证。

你可能还希望根据方案验证其他声明。 一些常见的验证包括:

  • 确保用户/组织已注册应用。
  • 使用 widsroles 声明确保用户具有适当的授权/权限。
  • 为了确保已达到某种身份验证的力度,例如采用多重身份验证。

验证 id_token后,可以开始与用户进行会话,并使用 id_token 中的声明获取应用中用户的相关信息。 此信息可用于显示、记录、个性化等。有关 id_tokens 和声明的详细信息,请阅读 AAD id_tokens

发送注销请求

如果想要将用户从应用注销,则清除应用的 Cookie 或结束与用户的会话是不够的。 还必须将用户重定向到 end_session_endpoint 进行注销。如果未能执行此操作,用户将能够重新对应用进行身份验证,而无需再次输入其凭据,因为他们将在 Azure AD 终结点拥有一个有效的单一登录会话。

只需将用户重定向到 OpenID Connect 元数据文档中列出的 end_session_endpoint

GET https://login.microsoftonline.com/common/oauth2/logout?
post_logout_redirect_uri=http%3A%2F%2Flocalhost%2Fmyapp%2F

参数 类型 说明
登出后重定向URI 推荐 成功注销后,用户应重定向到的 URL。此 URL 必须与在应用注册门户中为应用程序注册的重定向 URI 之一匹配。 如果未包含 post_logout_redirect_uri ,则用户会显示一条通用消息。

单一登录

将用户重定向到 end_session_endpoint时,Azure AD 会从浏览器中清除用户的会话。 但是,用户仍可能登录到使用 Azure AD 进行身份验证的其他应用程序。 为了使这些应用程序能够同时注销用户,Azure AD 会将 HTTP GET 请求发送到用户当前登录到的所有应用程序的已注册 LogoutUrl。 应用程序必须通过清除任何标识用户的会话并返回 200 响应来响应此请求。 如果要在应用程序中支持单一注销,则必须在应用程序的代码中实现此类 LogoutUrl。 可以从 Azure 门户设置 LogoutUrl

  1. 登录到 Azure 门户
  2. 单击页面右上角的帐户,选择 Active Directory。
  3. 在左侧导航面板中,依次选择 “Azure Active Directory”、“ 应用注册 ”和“应用程序”。
  4. 单击 “设置”,然后单击 “属性 ”并找到 “注销 URL ”文本框。

令牌获取

许多 Web 应用不仅需要让用户登录,还需要代表该用户使用 OAuth 访问 Web 服务。 此方案结合使用 OpenID Connect 进行用户身份验证,同时获取一个 authorization_code,该 authorization_code 可用于通过 OAuth 授权代码流 来获取 access_tokens

获取访问令牌

若要获取访问令牌,需要从上面修改登录请求:

// Line breaks for legibility only

GET https://login.microsoftonline.com/{tenant}/oauth2/authorize?
client_id=6731de76-14a6-49ae-97bc-6eba6914391e        // Your registered Application ID
&response_type=id_token+code
&redirect_uri=http%3A%2F%2Flocalhost%3a12345          // Your registered Redirect Uri, url encoded
&response_mode=form_post                              // `form_post' or 'fragment'
&scope=openid
&resource=https%3A%2F%2Fservice.contoso.com%2F        // The identifier of the protected resource (web API) that your application needs access to
&state=12345                                          // Any value, provided by your app
&nonce=678910                                         // Any value, provided by your app

通过在请求中包含权限范围并使用 response_type=code+id_tokenauthorize 终结点可确保用户已同意 scope 查询参数中指示的权限,并返回应用一个授权代码来交换访问令牌。

成功的响应

使用 redirect_uri发送到 response_mode=form_post 的成功响应如下所示:

POST /myapp/ HTTP/1.1
Host: localhost
Content-Type: application/x-www-form-urlencoded

id_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ik1uQ19WWmNB...&code=AwABAAAAvPM1KaPlrEqdFSBzjqfTGBCmLdgfSTLEMPGYuNHSUYBrq...&state=12345
参数 说明
身份令牌 应用请求的 id_token。 可以使用 id_token 来验证用户的标识,并开始与用户进行会话。
代码 应用请求的 authorization_code。 应用可以使用授权代码请求目标资源的访问令牌。 Authorization_codes生存期较短,通常在大约 10 分钟后过期。
如果请求中包含 state 参数,响应中就应该出现相同的值。 应用应该验证请求和响应中的 state 值是否完全相同。

错误响应

错误响应可能也发送到 redirect_uri ,让应用可以适当地处理:

POST /myapp/ HTTP/1.1
Host: localhost
Content-Type: application/x-www-form-urlencoded

error=access_denied&error_description=the+user+canceled+the+authentication
参数 说明
错误 可用于分类错误类型并响应错误的错误码字符串。
错误描述 帮助开发人员识别身份验证错误根本原因的特定错误消息。

有关可能的错误代码及其建议的客户端作的说明,请参阅 授权终结点错误的错误代码

一旦获得codeid_token授权后,就可以代表用户签入并获取访问令牌。 若要登录用户,必须验证 id_token,具体如上所述。 若要获取访问令牌,可以按照 OAuth 代码流文档中的“使用授权代码请求访问令牌”部分中所述的步骤进行作。

后续步骤