admin 管理员组文章数量: 1086019
I'm building a Blazor Web App (.NET 8) using Server interactivity and authenticating users via Microsoft Entra ID. Authentication works — I see the user is logged in, and their claims (oid, tid, etc.) are present.
My problems comes when I try to call the API from the blazor app:
var token = await _tokenAcquisition.GetAccessTokenForUserAsync(scopes, user);
The error from the above call is
MsalUiRequiredException: No account or login hint was passed to the AcquireTokenSilent call
Verbose MSAL logs say:
Found 0 accounts in MSAL cache
No refresh tokens or accounts found
Token cache could not satisfy silent request
This happens even though the user is authenticated.
My setup:
// Program.cs
builder.Services.AddBlazorServerAuthentication(builder.Configuration);
builder.Services.AddBlazorServerAuthorization();
// Add services to the container.
_ = builder.Services.AddRazorComponents()
.AddInteractiveServerComponents()
.AddMicrosoftIdentityConsentHandler();
_ = builder.Services.AddServerSideBlazor()
.AddMicrosoftIdentityConsentHandler();
_ = builder.Services.AddHttpContextAccessor();
_ = builder.Services.AddCascadingAuthenticationState();
= builder.Services.AddTransient<AccessTokenHandler>();
_ = builder.Services
.AddHttpClient("WebApiClient", client => client.BaseAddress = builder.Configuration.GetValue<Uri>("DownstreamApi:BaseUrl"))
.AddHttpMessageHandler<AccessTokenHandler>();
public static void AddBlazorServerAuthentication(this IServiceCollection services, IConfiguration configuration)
{
JwtSecurityTokenHandler.DefaultMapInboundClaims = false;
string[] scopes = configuration.GetValue<string>("DownstreamApi:Scopes")?.Split(';');
_ = services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddBearerToken()
.AddMicrosoftIdentityWebApp(options =>
{
configuration.Bind("AzureAd", options);
options.MaxAge = TimeSpan.FromHours(8);
options.AutomaticRefreshInterval = TimeSpan.FromMinutes(15);
options.Events.OnRemoteFailure = async context =>
{
try
{
AuthenticationProperties authenticationProperties = new()
{
RedirectUri = "/"
};
authenticationProperties.Parameters["logoutHint"] = context?.HttpContext?.User?.Identity?.Name;
await context.HttpContext.SignOutAsync(OpenIdConnectDefaults.AuthenticationScheme, authenticationProperties);
await context.HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
Console.WriteLine("Authentication failed. Logging out user silently");
context.HandleResponse();
await Task.CompletedTask;
}
catch (Exception)
{
throw;
}
};
})
.EnableTokenAcquisitionToCallDownstreamApi(scopes)
.AddInMemoryTokenCaches();
}
public static void AddBlazorServerAuthorization(this IServiceCollection services)
{
_ = services.AddAuthorization(options =>
{
options.FallbackPolicy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
});
}
//AccessTokenHandler
public class AccessTokenHandler : DelegatingHandler
{
private readonly ITokenAcquisition _tokenAcquisition;
private readonly IConfiguration _config;
private readonly IHttpContextAccessor _httpContextAccessor;
public AccessTokenHandler(ITokenAcquisition tokenAcquisition, IConfiguration config, IHttpContextAccessor httpContextAccessor)
{
_tokenAcquisition = tokenAcquisition;
_config = config;
_httpContextAccessor = httpContextAccessor;
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
string[] scopes = _config["DownstreamApi:Scopes"]?.Split(' ', StringSplitOptions.RemoveEmptyEntries);
if (scopes?.Length > 0)
{
string token = await _tokenAcquisition.GetAccessTokenForUserAsync(scopes,
user: _httpContextAccessor.HttpContext?.User,
authenticationScheme: OpenIdConnectDefaults.AuthenticationScheme);
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
}
return await base.SendAsync(request, cancellationToken);
}
}
"AzureAd": {
"Instance": "/",
"ClientId": "xxxxxxx",
"ClientSecret": "xyxyxyxyxy",
"TenantId": "zzzzzzzzz"
},
"DownstreamApi": {
"BaseUrl": "https://localhost:44385",
"Scopes": "api://yyyyyyyyyy/access_as_user"
}
本文标签: Blazor Web App (Server) EntraID authentication and downstream ApiStack Overflow
版权声明:本文标题:Blazor Web App (Server) EntraID authentication and downstream Api - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://roclinux.cn/p/1744088747a2531631.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论