经过大量研究和反复试验,我终于能够使用我的 Office365 帐户登录并访问 Azure 功能。
步骤 1 - 向 Azure Active Directory 注册您的应用服务应用
- 登录到 Azure 门户,然后导航到您的应用服务应用。将应用 URL 复制到 Azure 函数。你将使用它来配置你的 Azure Active Directory 应用程序注册。
- 导航到 Active Directory,然后选择应用程序注册,然后单击顶部的新应用程序注册以开始新的应用程序注册。
- 在创建页面中,为您的应用注册输入名称,选择 Web 应用/API 类型,在登录 URL 框中粘贴应用程序 URL(来自步骤 1)。然后点击创建。
- 几秒钟后,您应该会看到刚刚创建的新应用注册。
- 添加应用注册后,单击应用注册名称,单击顶部的设置,然后单击属性
- 在 App ID URI 框中,粘贴应用程序 URL(来自步骤 1),也在主页 URL 中粘贴应用程序 URL(来自步骤 1),然后单击保存
- 现在单击回复 URL,编辑回复 URL,粘贴应用程序 URL(从步骤 1 开始),修改协议以确保您有 https:// 协议(不是 http://),然后附加到末尾URL,/.auth/login/aad/callback(例如,https://contoso.azurewebsites.net/.auth/login/aad/callback)。单击保存。
- 此时,复制应用程序的应用程序 ID。保留以备后用。您将需要它来配置您的应用服务应用。
- 关闭已注册的应用页面。在 App 注册页面上,单击顶部的 Endpoints 按钮,然后复制联合元数据文档 URL。
- 打开一个新的浏览器窗口并通过粘贴并浏览到 XML 页面来导航到 URL。文档顶部是一个 EntityDescriptor 元素。找到 entityID 属性并复制其值。它用作您的颁发者 URL。您将配置您的应用程序以供以后使用。
步骤 2 - 将 Azure Active Directory 信息添加到应用服务应用
- 返回 Azure 门户,导航到应用服务应用。单击身份验证/授权。如果未启用身份验证/授权功能,请将开关转到 On。单击身份验证提供程序下的 Azure Active Directory 以配置您的应用程序。(可选)默认情况下,应用服务提供身份验证,但不限制对站点内容和 API 的授权访问。您必须在您的应用代码中授权用户。将请求未通过身份验证时采取的操作设置为使用 Azure Active Directory 登录。此选项要求对所有请求进行身份验证,并将所有未经身份验证的请求重定向到 Azure Active Directory 进行身份验证。
- 在 Active Directory 身份验证配置中,单击管理模式下的高级。将应用程序 ID 粘贴到客户端 ID 框中(来自第 8 步),然后单击确定。
- 在 Active Directory 身份验证配置页面上,单击保存。
第 3 步 - 配置本机客户端应用程序
Azure Active Directory 还允许您注册本机客户端,从而更好地控制权限映射。如果您希望使用诸如 Active Directory 身份验证库之类的库执行登录,则需要此功能。
- 在 Azure 门户中导航到 Azure Active Directory。
- 在左侧导航中,选择应用注册。点击顶部的新应用注册。
- 在创建页面中,输入您的应用注册名称。在应用程序类型中选择本机。
- 在重定向 URI 框中,使用 HTTPS 方案输入您站点的 /.auth/login/done 端点。此值应类似于https://contoso.azurewebsites.net/.auth/login/done。如果创建 Windows 应用程序,请改为使用包 SID 作为 URI。
- 单击创建。
- 添加应用程序注册后,选择它以将其打开。找到应用程序 ID 并记下此值。
- 单击所有设置 > 所需权限 > 添加 > 选择 API。
- 键入您之前注册的应用服务应用程序的名称以搜索它,然后选择它并单击选择。
- 选择访问。然后单击选择。然后单击完成。
以上说明取自https://docs.microsoft.com/en-us/azure/app-service/configure-authentication-provider-aad?toc=%2fazure%2fazure-functions%2ftoc.json
以下是我的更改,以使其与调用 Azure 函数的 WPF 应用程序一起使用
第 4 步 - 在服务应用程序中授权客户端应用程序
- 从第 3 步复制客户端应用程序 ID:
- 打开 Azure 活动目录
- 点击应用注册(预览)
- 点击第 1 步中注册的 Service App
- 单击公开 API
- 在授权的客户端应用程序下,单击添加客户端应用程序。
- 粘贴客户端 ID 并单击范围 https://{您的租户名称}.onmicrosoft.com/{您的服务应用 ID}/user_impersonation
- 单击添加应用程序
第 5 步 - 使服务应用程序多租户
- 打开 Azure 活动目录
- 点击应用注册(预览)
- 点击第 1 步中注册的 Service App
- 点击身份验证
- 在支持的帐户类型下选择“任何组织目录中的帐户”
- 您将收到一个错误。这是因为步骤 1 子步骤 6。我们需要根据租户域 {tenantname}.onmicrosoft.com 创建一个 App URI
- 导航到旧的应用注册(因为这在应用注册(预览版)中不可用,除非您编辑清单)
- 选择您的服务应用程序(您可能需要单击查看所有应用程序)
- 点击设置。然后单击属性。
- 在 App ID URI 下将其更改为 https://{ad tenant name}.onmicrosoft.com/{Service App ID}
- 确保 Multi-tenanted 设置为 Yes(应该是因为 Step 5 sub step 6.)
第 6 步 - 将范围添加到功能 APP
- 在 Azure 门户中打开函数应用并导航到 Authenticaiton
- 将 Active Directory 设置更改为具有来自服务 APP IE 的 API 范围权限的全部值的 Allowed Token Audiences
https://{AD TENANT}.onmicrosoft.com/{SERVICE APP ID}/user_impersonation
现在看代码
从您的客户端应用程序。安装 nuget Microsoft.Identity.Client
using Microsoft.Identity.Client;
using Newtonsoft.Json.Linq;
using System;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
namespace TestAzureFunctionLogin
{
public class ManualTestApp
{
static string ClientId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"; //replace with AppID from Client App Azure AD registration
static string ServiceId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"; //replace with AppID from Service App Azure AD registration
static string Scope = $"{ServiceId}/user_impersonation";
static string Authority = "https://login.microsoftonline.com/organizations";
string[] _scopes => new string[] { Scope };
private PublicClientApplication _clientApp = new PublicClientApplication(ClientId, Authority);
private AuthenticationResult authResult;
public PublicClientApplication ClientApp => _clientApp;
public async Task LoginAsync()
{
var user = (await ClientApp.GetAccountsAsync()).FirstOrDefault();
authResult = await ClientApp.AcquireTokenAsync(_scopes, user);
}
public async Task<string> CallAzureFunction(string url)
{
return await GetHttpContentWithToken(url, authResult.AccessToken);
}
//Code taken from somewhere on the Microsoft Website
public async Task<string> GetHttpContentWithToken(string url, string token)
{
var httpClient = new System.Net.Http.HttpClient();
System.Net.Http.HttpResponseMessage response;
try
{
var request = new System.Net.Http.HttpRequestMessage(System.Net.Http.HttpMethod.Get, url);
//Add the token in Authorization header
request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
response = await httpClient.SendAsync(request);
var content = await response.Content.ReadAsStringAsync();
return content;
}
catch (Exception ex)
{
return ex.ToString();
}
}
}
}