使用 Microsoft Identity 通过 Core 3.1 Web API 进行客户端 SPA 身份验证
Client SPA authentication with Core 3.1 Web API using Microsoft Identity
我认为我的主要问题是我应该使用哪个身份验证流程 - On-Behalf-Of 还是 Implicit Grant Flow?但是,我在 Startup.cs
中设置的身份验证和授权可能是错误的,我还差得远,如果是这样的话,我们深表歉意。
我在 Azure 中有一个现有的 Angular SPA,在 Azure 中还有一个 Net Framework API 运行。
网页API已移植到Net Core 3.1。
在我们的 Azure 目录中,我有两个已注册的应用程序。一个用于 API,另一个用于 SPA。我已经在 WEB API.
中的授权客户端下添加了 SPA 客户端 ID
值得注意的是,应用程序服务实际上 运行 在不同的目录中(我认为这很好但只是提一下)
这是 Azure AD 中的相关 Authentication/Authorization 设置。
private void ConfigureAzureAD(IServiceCollection services, IMvcBuilder mvcBuilder)
{
services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
.AddAzureAD(options => Configuration.Bind("AzureAd", options));
services.Configure<OpenIdConnectOptions>(AzureADDefaults.OpenIdScheme, options =>
{
options.Authority = options.Authority + "/v2.0/";
options.TokenValidationParameters.ValidateIssuer = true;
});
mvcBuilder.AddMvcOptions(options =>
{
var policy = new AuthorizationPolicyBuilder().
RequireAuthenticatedUser().
Build();
options.Filters.Add(new AuthorizeFilter(policy));
}).
SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseResponseCaching();
}
app.UseStaticFiles();
app.UseCors(CORS_POLICY);
if (UseAzureAD)
{
app.UseHttpsRedirection();
}
app.UseRouting();
app.UseCookiePolicy();
app.UseAuthorization();
app.UseAuthentication();
app.UseMvc();
}
我可以直接使用 API 并通过验证。
SPA 正在使用 Angular ADAL。如果我没看错,它将不适用于 Microsoft Identity V2 端点。 - 我们仍然需要升级到 MSAL,尽管我仍然无法理解最终的身份验证流程(我认为这是我的主要问题)。
目前,如果我点击 SPA,它将仅使用当前的 ADAL 配置进行身份验证,但是当它点击 API 时,并使用 ID 令牌重定向到 https://login.microsoftonline.com/{TenantId}/oauth2/v2.0/authorize?
。
它挂在重定向上,它们是 CORS 错误,因为源为空。我知道这是预期的,因为 SPA 配置不正确。
API 确实会调用 MS Graph API 来为用户获取组(但使用客户端 ID 和客户端密码来获取访问令牌来调用 MS Graph),所以我不不认为这意味着我需要使用 On-Behalf-Of-Flow(我确实看到了这个 post )?
我查看了此示例 https://github.com/Azure-Samples/ms-identity-javascript-angular-spa-aspnetcore-webapi 以了解隐式授权流程。
我在那个例子中确实注意到身份验证方案是 JwtBearerDefualts
这很有意义,因为 ID 令牌是 JWT,所以这让我质疑我的 API 启动配置。
这是在 API 中调用 MS Graph 的位,可能需要它来最好地回答我应该使用 2 个流中的哪一个(它再次获得带有客户端机密的访问令牌)。
private async Task<IReadOnlyCollection<string>> LoadReportGroupsCurrentUserCanRead()
{
var objectID = claimsPrincipal
.Claims
.FirstOrDefault(c => c.Type == "http://schemas.microsoft.com/identity/claims/objectidentifier")
?.Value;
var graphServiceClient = await GetGraphServiceClient();
var groups = await graphServiceClient
.Groups
.Request()
.GetAsync();
var memberGroups = await graphServiceClient
.Users[objectID]
.GetMemberGroups(true)
.Request()
.PostAsync();
return memberGroups.Select(mg => groups.SingleOrDefault(g => g.Id == mg))
.Where(g => g?.DisplayName?.EndsWith(" Report Group", StringComparison.InvariantCultureIgnoreCase) == true)
.Select(g => g.Description)
.Where(name => !string.IsNullOrWhiteSpace(name))
.ToArray();
}
private async Task<GraphServiceClient> GetGraphServiceClient()
{
string authority = new Uri(microsoftLogin, tenantID).AbsoluteUri;
var authenticationContext = new AuthenticationContext(authority);
var clientCredential = new ClientCredential(clientID, clientSecret);
var authenticationResult = await authenticationContext.AcquireTokenAsync("https://graph.microsoft.com", clientCredential);
var authProvider = new DelegateAuthenticationProvider(requestMessage =>
{
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("bearer", authenticationResult.AccessToken);
return Task.CompletedTask;
});
return new GraphServiceClient(authProvider);
}
最后,我认为我们的 SPA 使用的 Angular 版本不支持 Angular MSAL。我可以只使用 Vanilla MSAL JS(不要认为我们现在有时间升级 Angular)?
您应该使用 implicit flow and msal-angular。它支持从 4 到 9 的 Angular。此外,我不建议在 Angular 中使用 vanilla 库,除非没有其他选择。
ADAL 已弃用,不支持聚合应用程序模型(工作+个人帐户),因此您需要迁移到 MSAL。
关注Create web APIs with ASP.NET Core and Migrate from ASP.NET Core 2.2 to 3.0
删除这样的代码:
mvcBuilder.AddMvcOptions(options =>
{
var policy = new AuthorizationPolicyBuilder().
RequireAuthenticatedUser().
Build();
options.Filters.Add(new AuthorizeFilter(policy));
})
而是将您的控制器基于 Controller and decorate them with ApiController attribute。
还有这个,因为它是 .NET 3.1:
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
您的 MS Graph 身份验证正在使用 client credentials which is a commmon approach for the current app architecture. Provided you're not adding way too many highly privileged permissions 进行身份验证,那么应该没问题。
我认为我的主要问题是我应该使用哪个身份验证流程 - On-Behalf-Of 还是 Implicit Grant Flow?但是,我在 Startup.cs
中设置的身份验证和授权可能是错误的,我还差得远,如果是这样的话,我们深表歉意。
我在 Azure 中有一个现有的 Angular SPA,在 Azure 中还有一个 Net Framework API 运行。
网页API已移植到Net Core 3.1。
在我们的 Azure 目录中,我有两个已注册的应用程序。一个用于 API,另一个用于 SPA。我已经在 WEB API.
中的授权客户端下添加了 SPA 客户端 ID值得注意的是,应用程序服务实际上 运行 在不同的目录中(我认为这很好但只是提一下)
这是 Azure AD 中的相关 Authentication/Authorization 设置。
private void ConfigureAzureAD(IServiceCollection services, IMvcBuilder mvcBuilder)
{
services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
.AddAzureAD(options => Configuration.Bind("AzureAd", options));
services.Configure<OpenIdConnectOptions>(AzureADDefaults.OpenIdScheme, options =>
{
options.Authority = options.Authority + "/v2.0/";
options.TokenValidationParameters.ValidateIssuer = true;
});
mvcBuilder.AddMvcOptions(options =>
{
var policy = new AuthorizationPolicyBuilder().
RequireAuthenticatedUser().
Build();
options.Filters.Add(new AuthorizeFilter(policy));
}).
SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseResponseCaching();
}
app.UseStaticFiles();
app.UseCors(CORS_POLICY);
if (UseAzureAD)
{
app.UseHttpsRedirection();
}
app.UseRouting();
app.UseCookiePolicy();
app.UseAuthorization();
app.UseAuthentication();
app.UseMvc();
}
我可以直接使用 API 并通过验证。
SPA 正在使用 Angular ADAL。如果我没看错,它将不适用于 Microsoft Identity V2 端点。 - 我们仍然需要升级到 MSAL,尽管我仍然无法理解最终的身份验证流程(我认为这是我的主要问题)。
目前,如果我点击 SPA,它将仅使用当前的 ADAL 配置进行身份验证,但是当它点击 API 时,并使用 ID 令牌重定向到 https://login.microsoftonline.com/{TenantId}/oauth2/v2.0/authorize?
。
它挂在重定向上,它们是 CORS 错误,因为源为空。我知道这是预期的,因为 SPA 配置不正确。
API 确实会调用 MS Graph API 来为用户获取组(但使用客户端 ID 和客户端密码来获取访问令牌来调用 MS Graph),所以我不不认为这意味着我需要使用 On-Behalf-Of-Flow(我确实看到了这个 post
我查看了此示例 https://github.com/Azure-Samples/ms-identity-javascript-angular-spa-aspnetcore-webapi 以了解隐式授权流程。
我在那个例子中确实注意到身份验证方案是 JwtBearerDefualts
这很有意义,因为 ID 令牌是 JWT,所以这让我质疑我的 API 启动配置。
这是在 API 中调用 MS Graph 的位,可能需要它来最好地回答我应该使用 2 个流中的哪一个(它再次获得带有客户端机密的访问令牌)。
private async Task<IReadOnlyCollection<string>> LoadReportGroupsCurrentUserCanRead()
{
var objectID = claimsPrincipal
.Claims
.FirstOrDefault(c => c.Type == "http://schemas.microsoft.com/identity/claims/objectidentifier")
?.Value;
var graphServiceClient = await GetGraphServiceClient();
var groups = await graphServiceClient
.Groups
.Request()
.GetAsync();
var memberGroups = await graphServiceClient
.Users[objectID]
.GetMemberGroups(true)
.Request()
.PostAsync();
return memberGroups.Select(mg => groups.SingleOrDefault(g => g.Id == mg))
.Where(g => g?.DisplayName?.EndsWith(" Report Group", StringComparison.InvariantCultureIgnoreCase) == true)
.Select(g => g.Description)
.Where(name => !string.IsNullOrWhiteSpace(name))
.ToArray();
}
private async Task<GraphServiceClient> GetGraphServiceClient()
{
string authority = new Uri(microsoftLogin, tenantID).AbsoluteUri;
var authenticationContext = new AuthenticationContext(authority);
var clientCredential = new ClientCredential(clientID, clientSecret);
var authenticationResult = await authenticationContext.AcquireTokenAsync("https://graph.microsoft.com", clientCredential);
var authProvider = new DelegateAuthenticationProvider(requestMessage =>
{
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("bearer", authenticationResult.AccessToken);
return Task.CompletedTask;
});
return new GraphServiceClient(authProvider);
}
最后,我认为我们的 SPA 使用的 Angular 版本不支持 Angular MSAL。我可以只使用 Vanilla MSAL JS(不要认为我们现在有时间升级 Angular)?
您应该使用 implicit flow and msal-angular。它支持从 4 到 9 的 Angular。此外,我不建议在 Angular 中使用 vanilla 库,除非没有其他选择。
ADAL 已弃用,不支持聚合应用程序模型(工作+个人帐户),因此您需要迁移到 MSAL。
关注Create web APIs with ASP.NET Core and Migrate from ASP.NET Core 2.2 to 3.0 删除这样的代码:
mvcBuilder.AddMvcOptions(options =>
{
var policy = new AuthorizationPolicyBuilder().
RequireAuthenticatedUser().
Build();
options.Filters.Add(new AuthorizeFilter(policy));
})
而是将您的控制器基于 Controller and decorate them with ApiController attribute。
还有这个,因为它是 .NET 3.1:
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
您的 MS Graph 身份验证正在使用 client credentials which is a commmon approach for the current app architecture. Provided you're not adding way too many highly privileged permissions 进行身份验证,那么应该没问题。