我已经为WebApp和Api设置了身份验证/授权,并且可以正常工作。问题是当我必须引入其他的Api时(将从WebAPP中调用)。
局限性是,您不能在一次调用中询问具有混合Web api范围的令牌。这是服务(AAD)的限制,而不是库的限制。您必须向https:// {tenant} .onmicrosoft.com / api1 / read索取令牌然后您可以静默获取https:// {tenant} .onmicrosoft.com / api2 / read的令牌,因为这是两个不同的APIS。我从SO here和here]了解了更多信息
由于除了几行代码外没有完整的示例,所以我试图找到实现此解决方案的最佳方法。
当前我在启动中已设置身份验证
services.AddAuthentication(sharedOptions => { sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; sharedOptions.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme; }) services.AddAzureAdB2C(options => Configuration.Bind("AzureAdB2C", options)).AddCookie();
[AddAzureAdB2C是来自Samples的自定义扩展方法。
public static AuthenticationBuilder AddAzureAdB2C(this AuthenticationBuilder builder, Action<AzureAdB2COptions> configureOptions) { builder.Services.Configure(configureOptions); builder.Services.AddSingleton<IConfigureOptions<OpenIdConnectOptions>, OpenIdConnectOptionsSetup>(); builder.AddOpenIdConnect(); return builder; } public class OpenIdConnectOptionsSetup : IConfigureNamedOptions<OpenIdConnectOptions> { public void Configure(OpenIdConnectOptions options) { options.ClientId = AzureAdB2COptions.ClientId; options.Authority = AzureAdB2COptions.Authority; options.UseTokenLifetime = true; options.TokenValidationParameters = new TokenValidationParameters() { NameClaimType = "name" }; options.Events = new OpenIdConnectEvents() { OnRedirectToIdentityProvider = OnRedirectToIdentityProvider, OnRemoteFailure = OnRemoteFailure, OnAuthorizationCodeReceived = OnAuthorizationCodeReceived }; } public Task OnRedirectToIdentityProvider(RedirectContext context) { var defaultPolicy = AzureAdB2COptions.DefaultPolicy; if (context.Properties.Items.TryGetValue(AzureAdB2COptions.PolicyAuthenticationProperty, out var policy) && !policy.Equals(defaultPolicy)) { context.ProtocolMessage.Scope = OpenIdConnectScope.OpenIdProfile; context.ProtocolMessage.ResponseType = OpenIdConnectResponseType.IdToken; context.ProtocolMessage.IssuerAddress = context.ProtocolMessage.IssuerAddress.ToLower().Replace(defaultPolicy.ToLower(), policy.ToLower()); context.Properties.Items.Remove(AzureAdB2COptions.PolicyAuthenticationProperty); } else if (!string.IsNullOrEmpty(AzureAdB2COptions.ApiUrl)) { context.ProtocolMessage.Scope += $" offline_access {AzureAdB2COptions.ApiScopes}"; context.ProtocolMessage.ResponseType = OpenIdConnectResponseType.CodeIdToken; } return Task.FromResult(0); } }
我想必须在每行API的此行上设置范围,但这是管道的一部分。(否则,如果上面的OnRedirectToIdentityProvide方法的一部分)
context.ProtocolMessage.Scope += $" offline_access {AzureAdB2COptions.ApiScopes}";
以下是api客户端配置
services.AddHttpClient<IApiClient1, ApiClient1>() .AddHttpMessageHandler<API1AccessTokenHandler>(); services.AddHttpClient<IApiClient2, ApiClient2>() .AddHttpMessageHandler<API2AccessTokenHandler>();
以下是用于静默获取API1令牌的代码。
public class API1AccessTokenHandler : DelegatingHandler { protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { IConfidentialClientApplication publicClientApplication = null; try { // Retrieve the token with the specified scopes scopes = AzureAdB2COptions.ApiScopes.Split(' '); string signedInUserID = _httpContextAccessor.HttpContext.User.FindFirst(ClaimTypes.NameIdentifier).Value; publicClientApplication = ConfidentialClientApplicationBuilder.Create(AzureAdB2COptions.ClientId) .WithRedirectUri(AzureAdB2COptions.RedirectUri) .WithClientSecret(AzureAdB2COptions.ClientSecret) .WithB2CAuthority(AzureAdB2COptions.Authority) .Build(); new MSALStaticCache(signedInUserID, _httpContextAccessor.HttpContext).EnablePersistence(publicClientApplication.UserTokenCache); var accounts = await publicClientApplication.GetAccountsAsync(); result = await publicClientApplication.AcquireTokenSilent(scopes, accounts.FirstOrDefault()) .ExecuteAsync(); } catch (MsalUiRequiredException ex) { } if (result.AccessToken== null) { throw new Exception(); } request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken); return await base.SendAsync(request, cancellationToken); } }
下面是用于静默获取API2,API2AccessTokenHandler的令牌的代码。
public class API2AccessTokenHandler : DelegatingHandler { protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { IConfidentialClientApplication publicClientApplication = null; try { // Retrieve the token with the specified scopes scopes = Constants.Api2Scopes.Split(' '); string signedInUserID = _httpContextAccessor.HttpContext.User.FindFirst(ClaimTypes.NameIdentifier).Value; publicClientApplication = ConfidentialClientApplicationBuilder.Create(AzureAdB2COptions.ClientId) .WithRedirectUri(AzureAdB2COptions.RedirectUri) .WithClientSecret(AzureAdB2COptions.ClientSecret) .WithB2CAuthority(AzureAdB2COptions.Authority) .Build(); new MSALStaticCache(signedInUserID, _httpContextAccessor.HttpContext).EnablePersistence(publicClientApplication.UserTokenCache); var accounts = await publicClientApplication.GetAccountsAsync(); result = await publicClientApplication.AcquireTokenSilent(scopes, accounts.FirstOrDefault()) .ExecuteAsync(); } catch (MsalUiRequiredException ex) { } if (result.AccessToken== null) { throw new Exception(); } request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken); return await base.SendAsync(request, cancellationToken); } }
- [在获取令牌时传递范围没有帮助。代币始终为null。
我想在Api2的情况下单独调用Acquire令牌没有帮助,因为在Startup.cs中为Api1设置了范围。
请提供您的宝贵建议以及代码示例。
UPDATE:
我正在寻找类似于为IPublicClientApplication.AcquireTokenInteractive设计的WithExtraScopeToConsent。我需要类似的扩展,以用于AcquireTokenByAuthorizationCode的ConfidentialClientApplicationBuildercca.AcquireTokenByAuthorizationCode(AzureAdB2COptions.ApiScopes.Split(' '), code)
.WithExtraScopeToConsent(additionalScopeForAPi2)
.ExecuteAsync();
我已经为WebApp和Api设置了身份验证/授权,并且可以正常工作。问题是当我必须引入其他的Api时(将从WebAPP中调用)。限制是...
是的,对于同一个api,我们可以有多个作用域,而不是来自不同Apis的多个作用域。