如何在.NET 8 Blazor WASM中通过Keycloak OIDC获取令牌
.NET 8 Blazor WASM 集成Keycloak OIDC获取令牌的解决方案
一、修正OIDC配置,添加令牌接收事件处理
你可以通过扩展AddOidcAuthentication的配置,注册TokenReceived事件来捕获并存储令牌:
builder.Services.AddOidcAuthentication(options => { options.ProviderOptions.MetadataUrl = "https://my-domain.com/.well-known/openid-configuration"; options.ProviderOptions.Authority = "https://my-domain.com/realms/my-realm"; options.ProviderOptions.ClientId = "website-auth"; options.ProviderOptions.ResponseType = "id_token token"; // 必须包含openid scope,这是OIDC协议的必填项 options.ProviderOptions.Scope.Add("openid"); options.UserOptions.NameClaim = "preferred_username"; options.UserOptions.RoleClaim = ClaimTypes.Role; options.UserOptions.ScopeClaim = "scope"; }) .AddAccountClaimsPrincipalFactory<CustomAccountClaimsPrincipalFactory>() .ConfigureProviderOptions<OpenIdConnectProviderOptions, OidcProviderOptions>(options => { // 注册TokenReceived事件,捕获id_token并存储 options.Events.OnTokenReceived = context => { var idToken = context.TokenEndpointResponse.IdToken; if (!string.IsNullOrEmpty(idToken)) { // 示例:存储到浏览器localStorage context.HttpContext.RequestServices.GetRequiredService<IJSRuntime>() .InvokeVoidAsync("localStorage.setItem", "keycloak_id_token", idToken); } return Task.CompletedTask; }; });
二、正确使用IAccessTokenProvider获取令牌
你遇到的空令牌问题,大概率是注入方式或调用时机错误:
- 直接注入IAccessTokenProvider:无需通过
IAccessTokenProviderAccessor,直接在组件/服务中注入即可:
private readonly IAccessTokenProvider _tokenProvider; public YourComponent(IAccessTokenProvider tokenProvider) { _tokenProvider = tokenProvider; }
- 确保在已认证状态下调用:只有用户登录后才能获取有效令牌,调用前先验证认证状态:
var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync(); if (authState.User.Identity?.IsAuthenticated == true) { var tokenResult = await _tokenProvider.RequestAccessToken(); if (tokenResult.TryGetToken(out var token)) { var accessToken = token.Value; // 也可从认证状态中提取id_token var idToken = authState.User.FindFirst("id_token")?.Value; } }
- 指定请求的Scope:如果需要特定权限的令牌,可在请求时明确Scope:
var tokenResult = await _tokenProvider.RequestAccessToken(new AccessTokenRequestOptions { Scopes = new[] { "openid", "profile" } });
三、从认证状态直接提取令牌
Keycloak返回的令牌通常会以Claim形式存在用户认证信息中,可直接提取:
var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync(); var idToken = authState.User.Claims.FirstOrDefault(c => c.Type == "id_token")?.Value; var accessToken = authState.User.Claims.FirstOrDefault(c => c.Type == "access_token")?.Value;
如果Claim中没有对应令牌,可在自定义CustomAccountClaimsPrincipalFactory中添加:
public class CustomAccountClaimsPrincipalFactory : AccountClaimsPrincipalFactory<RemoteUserAccount> { public CustomAccountClaimsPrincipalFactory(IAccessTokenProviderAccessor accessor) : base(accessor) { } public override async ValueTask<ClaimsPrincipal> CreateUserAsync( RemoteUserAccount account, RemoteAuthenticationUserOptions options) { var principal = await base.CreateUserAsync(account, options); // 将令牌添加到Claims集合 if (account.AdditionalProperties.TryGetValue("id_token", out var idToken)) { ((ClaimsIdentity)principal.Identity).AddClaim(new Claim("id_token", idToken.ToString())); } if (account.AdditionalProperties.TryGetValue("access_token", out var accessToken)) { ((ClaimsIdentity)principal.Identity).AddClaim(new Claim("access_token", accessToken.ToString())); } return principal; } }
四、常见问题排查
- 确认
ResponseType设置为id_token token,确保同时返回两种令牌 - 检查Keycloak客户端配置,将"Access Type"设为"public"(Blazor WASM属于单页公开应用)
- 确保Scope包含
openid,缺少该Scope会导致OIDC流程不完整 - 调用
RequestAccessToken前,确认用户已完成登录跳转流程
内容的提问来源于stack exchange,提问作者Dmitriy Kudinov
相关产品推荐
相关产品推荐

