从 Azure AD 获取用于从客户端应用程序授权请求的令牌Acquire a token from Azure AD for authorizing requests from a client application

将 Azure Active Directory (Azure AD) 与 Azure Blob 存储和队列存储配合使用的主要优点在于不再需要在代码中存储凭据。A key advantage of using Azure Active Directory (Azure AD) with Azure Blob storage or Queue storage is that your credentials no longer need to be stored in your code. 可以从 Microsoft 标识平台(以前称为 Azure AD)请求 OAuth 2.0 访问令牌。Instead, you can request an OAuth 2.0 access token from the Microsoft identity platform (formerly Azure AD). Azure AD 对运行应用程序的安全主体(用户、组或服务主体)进行身份验证。Azure AD authenticates the security principal (a user, group, or service principal) running the application. 如果身份验证成功,Azure AD 会将访问令牌返回应用程序,应用程序可随之使用访问令牌对 Azure Blob 存储或队列存储请求授权。If authentication succeeds, Azure AD returns the access token to the application, and the application can then use the access token to authorize requests to Azure Blob storage or Queue storage.

本文介绍如何配置本机应用程序或 Web 应用程序,以便在 Microsoft 标识平台 2.0 中进行身份验证。This article shows how to configure your native application or web application for authentication with Microsoft identity platform 2.0. 代码示例使用 .NET,但其他语言使用类似的方法。The code example features .NET, but other languages use a similar approach. 有关 Microsoft 标识平台 2.0 的详细信息,请参阅 Microsoft 标识平台 (v2.0) 概述For more information about Microsoft identity platform 2.0, see Microsoft identity platform (v2.0) overview.

有关 OAuth 2.0 代码授权流的概述,请参阅使用 OAuth 2.0 代码授权流来授权访问 Azure Active Directory Web 应用程序For an overview of the OAuth 2.0 code grant flow, see Authorize access to Azure Active Directory web applications using the OAuth 2.0 code grant flow.

将角色分配给 Azure AD 安全主体Assign a role to an Azure AD security principal

若要从 Azure 存储应用程序对安全主体进行身份验证,请先为该安全主体配置基于角色的访问控制 (RBAC) 设置。To authenticate a security principal from your Azure Storage application, first configure role-based access control (RBAC) settings for that security principal. Azure 存储定义包含容器和队列权限的 Azure 内置角色。Azure Storage defines Azure built-in roles that encompass permissions for containers and queues. 如果将 Azure 角色分配给安全主体,该安全主体会获得该资源的访问权限。When the Azure role is assigned to a security principal, that security principal is granted access to that resource. 有关详细信息,请参阅使用 RBAC 管理对 Azure Blob 和队列数据的访问权限For more information, see Manage access rights to Azure Blob and Queue data with RBAC.

将应用程序注册到 Azure AD 租户Register your application with an Azure AD tenant

使用 Azure AD 授予存储资源访问权限的第一步是,通过 Azure 门户在 Azure AD 租户中注册客户端应用程序。The first step in using Azure AD to authorize access to storage resources is registering your client application with an Azure AD tenant from the Azure portal. 注册客户端应用程序时,需要向 Azure AD 提供关于应用程序的信息。When you register your client application, you supply information about the application to Azure AD. Azure AD 随后会提供客户端 ID(也称为应用程序 ID)。在运行时,可以使用该 ID 将应用程序与 Azure AD 关联。Azure AD then provides a client ID (also called an application ID) that you use to associate your application with Azure AD at runtime. 若要详细了解客户端 ID,请参阅 Azure Active Directory 中的应用程序对象和服务主体对象To learn more about the client ID, see Application and service principal objects in Azure Active Directory.

若要注册 Azure 存储应用程序,请遵循以下文章中所述的步骤:快速入门:将应用程序注册到 Microsoft 标识平台To register your Azure Storage application, follow the steps shown in Quickstart: Register an application with the Microsoft identity platform. 下图显示了用于注册 Web 应用程序的常用设置:The following image shows common settings for registering a web application:

显示如何向 Azure AD 注册存储应用程序的屏幕截图

备注

如果将应用程序注册为本机应用程序,可以为重定向 URI 指定任何有效的 URI。If you register your application as a native application, you can specify any valid URI for the Redirect URI. 对于本机应用程序,此值不一定要是实际的 URL。For native applications, this value does not have to be a real URL. 对于 Web 应用程序,重定向 URI 必须是有效的 URI,因为它指定了要向哪个 URL 提供令牌。For web applications, the redirect URI must be a valid URI, because it specifies the URL to which tokens are provided.

注册应用程序后,可在“设置”下看到应用程序 ID(或客户端 ID):After you've registered your application, you'll see the application ID (or client ID) under Settings:

显示客户端 ID 的屏幕截图

有关向 Azure AD 注册应用程序的详细信息,请参阅将应用程序与 Azure Active Directory 集成。For more information about registering an application with Azure AD, see Integrating applications with Azure Active Directory.

向 Azure 存储授予注册应用权限Grant your registered app permissions to Azure Storage

接下来,授予应用程序权限以调用 Azure 存储 API。Next, grant your application permissions to call Azure Storage APIs. 借助此步骤,应用程序可授权使用 Azure AD 请求 Azure 存储。This step enables your application to authorize requests to Azure Storage with Azure AD.

  1. 在已注册的应用程序的“概述”页上,选择“查看 API 权限”。 On the Overview page for your registered application, select View API Permissions.

  2. 在“API 权限”部分中,依次选择“添加权限”、“Microsoft API”。 In the API permissions section, select Add a permission and choose Microsoft APIs.

  3. 从结果列表中选择“Azure 存储”以显示“请求 API 权限”窗格。Select Azure Storage from the list of results to display the Request API permissions pane.

  4. 在“应用程序需要哪种类型的权限?”下,注意可用的权限类型是“委托的权限”。 Under What type of permissions does your application require?, observe that the available permission type is Delegated permissions. 默认已自动选择此选项。This option is selected for you by default.

  5. 在“请求 API 权限”窗格的“选择权限”部分,选中“user_impersonation”旁边的复选框,然后单击“添加权限”。 In the Select permissions section of the Request API permissions pane, select the checkbox next to user_impersonation, then click Add permissions.

    显示存储权限的屏幕截图

现在,“API 权限”窗格会显示已注册的 Azure AD 应用程序有权访问 Microsoft Graph 和 Azure 存储 API。The API permissions pane now shows that your registered Azure AD application has access to both the Microsoft Graph and Azure Storage APIs. 首次向 Azure AD 注册应用时,系统会自动授予对 Microsoft Graph 的权限。Permissions are granted to Microsoft Graph automatically when you first register your app with Azure AD.

显示注册应用权限的屏幕截图

创建客户端机密Create a client secret

请求令牌时,应用程序需要使用客户端机密来证明其身份。The application needs a client secret to prove its identity when requesting a token. 若要添加客户端机密,请执行以下步骤:To add the client secret, follow these steps:

  1. 在 Azure 门户中导航到你的应用注册。Navigate to your app registration in the Azure portal.

  2. 选择“证书和机密”设置。Select the Certificates & secrets setting.

  3. 在“客户端机密”下,单击“新建客户端机密”以创建新的机密。 Under Client secrets, click New client secret to create a new secret.

  4. 提供机密说明,并选择所需的过期时间间隔。Provide a description for the secret, and choose the desired expiration interval.

  5. 请马上将新机密的值复制到安全位置。Immediately copy the value of the new secret to a secure location. 完整的值只会显示一次。The full value is displayed to you only once.

    显示客户端机密的屏幕截图

用于获取令牌的客户端库Client libraries for token acquisition

注册应用程序并向其授予 Azure Blob 存储或队列存储中的数据的访问权限后,可将代码添加到应用程序,以便对安全主体进行身份验证并获取 OAuth 2.0 令牌。Once you have registered your application and granted it permissions to access data in Azure Blob storage or Queue storage, you can add code to your application to authenticate a security principal and acquire an OAuth 2.0 token. 若要进行身份验证并获取令牌,可以使用 Microsoft 标识平台身份验证库,或其他支持 OpenID Connect 1.0 的开源库。To authenticate and acquire the token, you can use either one of the Microsoft identity platform authentication libraries or another open-source library that supports OpenID Connect 1.0. 然后,应用程序可以使用访问令牌来授权针对 Azure Blob 存储或队列存储发出的请求。Your application can then use the access token to authorize a request against Azure Blob storage or Queue storage.

有关支持获取令牌的方案的列表,请参阅 Microsoft 身份验证库内容身份验证流部分。For a list of scenarios for which acquiring tokens is supported, see the authentication flows section of the Microsoft Authentication Library content.

使用 Azure AD 进行身份验证的已知值Well-known values for authentication with Azure AD

若要使用 Azure AD 验证安全主体的身份,需要在代码中包含一些已知值。To authenticate a security principal with Azure AD, you need to include some well-known values in your code.

Azure AD 颁发机构Azure AD authority

对于 Azure,基本 Azure AD 颁发机构如下所示,其中 tenant-id 是 Active Directory 租户 ID(或目录 ID):For Azure, the base Azure AD authority is as follows, where tenant-id is your Active Directory tenant ID (or directory ID):

https://login.partner.microsoftonline.cn/<tenant-id>/

租户 ID 用于标识要用于身份验证的 Azure AD 租户。The tenant ID identifies the Azure AD tenant to use for authentication. 它也称为目录 ID。It is also referred to as the directory ID. 若要检索租户 ID,请在 Azure 门户中导航到应用注册的“概述”页,并从中复制该值。To retrieve the tenant ID, navigate to the Overview page for your app registration in the Azure portal, and copy the value from there.

Azure 存储资源 IDAzure Storage resource ID

Azure AD 资源 ID 指示一个受众,其令牌在发出后可以用于提供对 Azure 资源的访问权限。An Azure AD resource ID indicates the audience for which a token that is issued can be used to provide access to an Azure resource. 在使用 Azure 存储时,资源 ID 可能特定于单个存储帐户,也可能适用于任何存储帐户。In the case of Azure Storage, the resource ID may be specific to a single storage account, or it may apply to any storage account. 下表介绍可为资源 ID 提供的值:The following table describes the values that you can provide for the resource ID:

资源 IDResource ID 说明Description
https://<account>.blob.core.chinacloudapi.cn

https://<account>.queue.core.chinacloudapi.cn
给定存储帐户的服务终结点。The service endpoint for a given storage account. 使用此值可获取一个用于对请求授权的令牌,这些请求仅针对该特定 Azure 存储帐户和服务。Use this value to acquire a token for authorizing requests to that specific Azure Storage account and service only. 将括号中的值替换为存储帐户的名称。Replace the value in brackets with the name of your storage account.
https://storage.azure.com/ 用于获取一个可对请求授权的令牌,这些请求针对任何 Azure 存储帐户。Use to acquire a token for authorizing requests to any Azure Storage account.

.NET 代码示例:创建块 Blob.NET code example: Create a block blob

代码示例展示如何从 Azure AD 获取访问令牌。The code example shows how to get an access token from Azure AD. 访问令牌用于对指定用户进行身份验证,然后授权用于创建块 blob 的请求。The access token is used to authenticate the specified user and then authorize a request to create a block blob. 若要让此示例能够正常工作,请首先遵循上述部分列出的步骤。To get this sample working, first follow the steps outlined in the preceding sections.

若要请求令牌,需要获取应用注册中的以下值:To request the token, you will need the following values from your app's registration:

  • Azure AD 域的名称。The name of your Azure AD domain. 可从 Azure Active Directory 的“概述”页检索此值。Retrieve this value from the Overview page of your Azure Active Directory.
  • 租户(或目录)ID。The tenant (or directory) ID. 可从应用注册的“概述”页检索此值。Retrieve this value from the Overview page of your app registration.
  • 客户端(或应用程序)ID。The client (or application) ID. 可从应用注册的“概述”页检索此值。Retrieve this value from the Overview page of your app registration.
  • 客户端重定向 URI。The client redirection URI. 可应用注册的“身份验证”设置检索此值。Retrieve this value from the Authentication settings for your app registration.
  • 客户端机密的值。The value of the client secret. 可从先前复制到的位置检索此值。Retrieve this value from the location to which you previously copied it.

创建存储帐户和容器Create a storage account and container

若要运行代码示例,请在 Azure Active Directory 所在的同一订阅中创建一个存储帐户。To run the code sample, create a storage account within the same subscription as your Azure Active Directory. 然后在该存储帐户中创建一个容器。Then create a container within that storage account. 示例代码将在此容器中创建块 Blob。The sample code will create a block blob in this container.

接下来,将“存储 Blob 数据参与者”角色显式分配到用于运行示例代码的用户帐户。Next, explicitly assign the Storage Blob Data Contributor role to the user account under which you will run the sample code. 若要了解如何在 Azure 门户中分配此角色的说明,请参阅在 Azure 门户中使用 RBAC 授予对 Azure Blob 和队列数据的访问权限For instructions on how to assign this role in the Azure portal, see Grant access to Azure blob and queue data with RBAC in the Azure portal.

备注

创建 Azure 存储帐户时,系统不会自动向你分配通过 Azure AD 访问数据的权限。When you create an Azure Storage account, you are not automatically assigned permissions to access data via Azure AD. 你必须为自己显式分配一个用于 Azure 存储的 Azure 角色。You must explicitly assign yourself an Azure role for Azure Storage. 可以在订阅、资源组、存储帐户、容器或队列级别分配它。You can assign it at the level of your subscription, resource group, storage account, or container or queue.

创建一个授权使用 Azure AD 访问 Blob 存储的 Web 应用程序Create a web application that authorizes access to Blob storage with Azure AD

当应用程序访问 Azure 存储时,它是在代表用户进行访问,这意味着,这是在使用已登录用户的权限访问 blob 或队列资源。When your application accesses Azure Storage, it does so on the user's behalf, meaning that blob or queue resources are accessed using the permissions of the user who is logged in. 若要尝试运行此代码示例,需要提供一个可以提示用户使用 Azure AD 标识登录的 Web 应用程序。To try this code example, you need a web application that prompts the user to sign in using an Azure AD identity. 你可以创建自己的应用程序,也可以使用 Azure 提供的示例应用程序。You can create your own, or use the sample application provided by Azure.

GitHub 上提供了一个已完成的示例 Web 应用程序,该应用程序可获取令牌,并使用该令牌在 Azure 存储中创建 Blob。A completed sample web application that acquires a token and uses it to create a blob in Azure Storage is available on GitHub. 查看并运行这个已完成的示例可能有助于理解代码示例。Reviewing and running the completed sample may be helpful for understanding the code examples. 有关如何运行已完成的示例的说明,请参阅标题为查看和运行已完成的示例的部分。For instructions about how to run the completed sample, see the section titled View and run the completed sample.

添加引用和 using 语句Add references and using statements

在 Visual Studio 中安装 Azure 存储客户端库。From Visual Studio, install the Azure Storage client library. 在“工具”菜单中选择“NuGet 包管理器”,然后选择“包管理器控制台” 。From the Tools menu, select NuGet Package Manager, then Package Manager Console. 在控制台窗口中键入以下命令,以安装适用于 .NET 的 Azure 存储客户端库中的所需包:Type the following commands into the console window to install the necessary packages from the Azure Storage client library for .NET:

Install-Package Microsoft.Azure.Storage.Blob
Install-Package Microsoft.Azure.Storage.Common

接下来,将以下 using 语句添加到 HomeController.cs 文件:Next, add the following using statements to the HomeController.cs file:

using Microsoft.Identity.Client; //MSAL library for getting the access token
using Microsoft.WindowsAzure.Storage.Auth;
using Microsoft.WindowsAzure.Storage.Blob;

创建块 BlobCreate a block blob

添加以下代码片段以创建块 Blob:Add the following code snippet to create a block blob:

private static async Task<string> CreateBlob(string accessToken)
{
    // Create a blob on behalf of the user
    TokenCredential tokenCredential = new TokenCredential(accessToken);
    StorageCredentials storageCredentials = new StorageCredentials(tokenCredential);

    // Replace the URL below with your storage account URL
    CloudBlockBlob blob =
        new CloudBlockBlob(
            new Uri("https://<storage-account>.blob.core.chinacloudapi.cn/<container>/Blob1.txt"),
            storageCredentials);
    await blob.UploadTextAsync("Blob created by Azure AD authenticated user.");
    return "Blob successfully created";
}

备注

若要授权使用 OAuth 2.0 令牌执行 Blob 和队列操作,必须使用 HTTPS。To authorize blob and queue operations with an OAuth 2.0 token, you must use HTTPS.

在上面的示例中,.NET 客户端库处理请求的授权以创建块 blob。In the example above, the .NET client library handles the authorization of the request to create the block blob. 其他语言的 Azure 存储客户端库也可以自动处理请求授权。Azure Storage client libraries for other languages also handle the authorization of the request for you. 但是,如果正在使用 REST API 通过 OAuth 标记调用 Azure 存储操作,之后将需要使用 OAuth 标记对请求进行授权。However, if you are calling an Azure Storage operation with an OAuth token using the REST API, then you'll need to authorize the request using the OAuth token.

若要使用 OAuth 访问令牌调用 Blob 和队列服务操作,请使用“持有者令牌”方案在“授权”标头中传递访问令牌,并指定服务版本 2017-11-09 或更高版本,如以下示例所示 :To call Blob and Queue service operations using OAuth access tokens, pass the access token in the Authorization header using the Bearer scheme, and specify a service version of 2017-11-09 or higher, as shown in the following example:

GET /container/file.txt HTTP/1.1
Host: mystorageaccount.blob.core.chinacloudapi.cn
x-ms-version: 2017-11-09
Authorization: Bearer eyJ0eXAiOnJKV1...Xd6j

从 Azure AD 获取 OAuth 令牌Get an OAuth token from Azure AD

接下来,添加代表用户从 Azure AD 请求令牌的方法。Next, add a method that requests a token from Azure AD on the behalf of the user. 此方法定义要授予的权限的范围。This method defines the scope for which permissions are to be granted. 若要详细了解权限和范围,请参阅 Microsoft 标识平台终结点中的权限和许可For more information about permissions and scopes, see Permissions and consent in the Microsoft identity platform endpoint.

请使用资源 ID 来构造获取的令牌的范围。Use the resource ID to construct the scope for which to acquire the token. 此示例构造范围时,将资源 ID 与内置的 user_impersonation 范围配合使用,后者指示令牌是代表用户请求的。The example constructs the scope by using the resource ID together with the built-in user_impersonation scope, which indicates that the token is being requested on behalf of the user.

请记住,可能需要为用户呈现一个界面,让用户允许代表他/她来请求令牌。Keep in mind that you may need to present the user with an interface that enables the user to consent to request the token their behalf. 必须进行许可时,此示例会捕获 MsalUiRequiredException 并调用另一方法,促进许可请求:When consent is necessary, the example catches the MsalUiRequiredException and calls another method to facilitate the request for consent:

public async Task<IActionResult> Blob()
{
    var scopes = new string[] { "https://storage.azure.com/user_impersonation" };
    try
    {
        var accessToken =
            await _tokenAcquisition.GetAccessTokenOnBehalfOfUser(HttpContext, scopes);
        ViewData["Message"] = await CreateBlob(accessToken);
        return View();
    }
    catch (MsalUiRequiredException ex)
    {
        AuthenticationProperties properties =
            BuildAuthenticationPropertiesForIncrementalConsent(scopes, ex);
        return Challenge(properties);
    }
}

许可是指用户进行应用程序授权,让应用程序代表自己来访问受保护资源的过程。Consent is the process of a user granting authorization to an application to access protected resources on their behalf. Microsoft 标识平台 2.0 支持增量许可,这意味着,安全主体最初可以请求极少量的一组权限,以后可按需添加权限。The Microsoft identity platform 2.0 supports incremental consent, meaning that a security principal can request a minimum set of permissions initially and add permissions over time as needed. 当代码请求访问令牌时,请在 scope 参数中指定应用在任意给定时间所需的权限范围。When your code requests an access token, specify the scope of permissions that your app needs at any given time by in the scope parameter. 有关增量许可的详细信息,请参阅为何要更新到 Microsoft 标识平台 (v2.0)?中的“增量许可和动态许可”部分。For more information about incremental consent, see the section titled Incremental and dynamic consent in Why update to Microsoft identity platform (v2.0)?.

以下方法将会构造用于请求增量许可的身份验证属性:The following method constructs the authentication properties for requesting incremental consent:

private AuthenticationProperties BuildAuthenticationPropertiesForIncrementalConsent(string[] scopes,
                                                                                    MsalUiRequiredException ex)
{
    AuthenticationProperties properties = new AuthenticationProperties();

    // Set the scopes, including the scopes that MSAL.NET needs for the token cache.
    string[] additionalBuildInScopes = new string[] { "openid", "offline_access", "profile" };
    properties.SetParameter<ICollection<string>>(OpenIdConnectParameterNames.Scope,
                                                 scopes.Union(additionalBuildInScopes).ToList());

    // Attempt to set the login_hint so that the logged-in user is not presented
    // with an account selection dialog.
    string loginHint = HttpContext.User.GetLoginHint();
    if (!string.IsNullOrWhiteSpace(loginHint))
    {
        properties.SetParameter<string>(OpenIdConnectParameterNames.LoginHint, loginHint);

        string domainHint = HttpContext.User.GetDomainHint();
        properties.SetParameter<string>(OpenIdConnectParameterNames.DomainHint, domainHint);
    }

    // Specify any additional claims that are required (for instance, MFA).
    if (!string.IsNullOrEmpty(ex.Claims))
    {
        properties.Items.Add("claims", ex.Claims);
    }

    return properties;
}

查看和运行已完成的示例View and run the completed sample

若要运行示例应用程序,请先从 GitHub 克隆或下载它。To run the sample application, first clone or download it from GitHub. 然后根据以下部分所述更新应用程序。Then update the application as described in the following sections.

在设置文件中提供值Provide values in the settings file

接下来,使用自己的值更新 appsettings.json 文件,如下所示:Next, update the appsettings.json file with your own values, as follows:

{
  "AzureAd": {
    "Instance": "https://login.partner.microsoftonline.cn/",
    "Domain": "<azure-ad-domain-name>.partner.onmschina.cn",
    "TenantId": "<tenant-id>",
    "ClientId": "<client-id>",
    "CallbackPath": "/signin-oidc",
    "SignedOutCallbackPath ": "/signout-callback-oidc",

    // To call an API
    "ClientSecret": "<client-secret>"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Warning"
    }
  },
  "AllowedHosts": "*"
}

更新存储帐户和容器名称Update the storage account and container name

HomeController.cs 文件中,更新引用块 Blob 的 URI,以使用存储帐户和容器的名称:In the HomeController.cs file, update the URI that references the block blob to use the name of your storage account and container:

CloudBlockBlob blob = new CloudBlockBlob(
                      new Uri("https://<storage-account>.blob.core.chinacloudapi.cn/<container>/Blob1.txt"),
                      storageCredentials);

启用隐式授权流Enable implicit grant flow

若要运行该示例,可能需要为应用注册配置隐式授权流。To run the sample, you may need to configure the implicit grant flow for your app registration. 执行以下步骤:Follow these steps:

  1. 在 Azure 门户中导航到你的应用注册。Navigate to your app registration in the Azure portal.

  2. 在“管理”部分中,选择“身份验证”设置。 In the Manage section, select the Authentication setting.

  3. 在“隐式授权”部分中,选中相应的复选框以启用 ID 令牌,如下图所示:In the Implicit grant section, select the check box to enable ID tokens, as shown in the following image:

    显示如何启用隐式授权流设置的屏幕截图

更新 localhost 使用的端口Update the port used by localhost

运行该示例时,你可能会发现,需要更新应用注册中指定重定向 URI,以使用在运行时分配的 localhost 端口。When you run the sample, you may find that you need to update the redirect URI specified in your app registration to use the localhost port assigned at runtime. 若要更新重定向 URI 以使用分配的端口,请执行以下步骤:To update the redirect URI to use the assigned port, follow these steps:

  1. 在 Azure 门户中导航到你的应用注册。Navigate to your app registration in the Azure portal.

  2. 在“管理”部分中,选择“身份验证”设置。 In the Manage section, select the Authentication setting.

  3. 在“重定向 URI”下编辑端口,使之与示例应用程序使用的端口相匹配,如下图所示:Under Redirect URIs, edit the port to match that used by the sample application, as shown in the following image:

    显示应用注册的重定向 URI 的屏幕截图

后续步骤Next steps