Blazor WASM:通过JavaScript完成Auth0认证后如何注册访问令牌?
在Blazor WASM中利用Auth0令牌完成用户认证
1. 处理登录返回结果
首先处理Auth0弹窗返回的结果:
- 先检查
error字段,若不为空,直接提示用户登录失败(比如弹窗显示错误信息) - 若返回有效令牌,将
accessToken、idToken、refreshToken安全存储。推荐使用Blazor的ProtectedLocalStorage(比普通localStorage多一层加密),示例代码:
@inject ProtectedLocalStorage ProtectedLocalStorage // 存储令牌 await ProtectedLocalStorage.SetAsync("auth0_access_token", accessToken); await ProtectedLocalStorage.SetAsync("auth0_id_token", idToken); await ProtectedLocalStorage.SetAsync("auth0_refresh_token", refreshToken);
2. 解析ID Token并构建认证状态
ID Token是JWT格式,包含用户核心身份信息(如姓名、邮箱、用户ID),需解析后供Blazor的认证系统使用:
- 先引入
System.IdentityModel.Tokens.JwtNuGet包 - 编写解析方法:
using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; public ClaimsPrincipal ParseIdToken(string idToken) { var handler = new JwtSecurityTokenHandler(); var jwtToken = handler.ReadJwtToken(idToken); return new ClaimsPrincipal(new ClaimsIdentity(jwtToken.Claims, "Auth0")); }
- 自定义
AuthenticationStateProvider,让Blazor感知用户状态:
public class Auth0AuthenticationStateProvider : AuthenticationStateProvider { private readonly ProtectedLocalStorage _protectedLocalStorage; public Auth0AuthenticationStateProvider(ProtectedLocalStorage protectedLocalStorage) { _protectedLocalStorage = protectedLocalStorage; } public override async Task<AuthenticationState> GetAuthenticationStateAsync() { var anonymous = new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity())); try { var idTokenResult = await _protectedLocalStorage.GetAsync<string>("auth0_id_token"); if (idTokenResult.Success && !string.IsNullOrEmpty(idTokenResult.Value)) { var user = ParseIdToken(idTokenResult.Value); return new AuthenticationState(user); } return anonymous; } catch { return anonymous; } } // 登录成功后调用此方法更新状态 public async Task NotifyUserAuthenticated() { var idTokenResult = await _protectedLocalStorage.GetAsync<string>("auth0_id_token"); var user = ParseIdToken(idTokenResult.Value); NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(user))); } // 注销后调用此方法更新状态 public void NotifyUserLogout() { NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity())))); } }
然后在Program.cs中注册这个Provider:
builder.Services.AddScoped<AuthenticationStateProvider, Auth0AuthenticationStateProvider>(); builder.Services.AddAuthorizationCore();
3. 使用Access Token调用受保护API
调用后端受保护接口时,需在请求头中携带Access Token:
- 自定义
AuthorizationMessageHandler自动添加令牌:
public class Auth0AuthorizationMessageHandler : DelegatingHandler { private readonly ProtectedLocalStorage _protectedLocalStorage; public Auth0AuthorizationMessageHandler(ProtectedLocalStorage protectedLocalStorage) { _protectedLocalStorage = protectedLocalStorage; } protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { var tokenResult = await _protectedLocalStorage.GetAsync<string>("auth0_access_token"); if (tokenResult.Success && !string.IsNullOrEmpty(tokenResult.Value)) { request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", tokenResult.Value); } return await base.SendAsync(request, cancellationToken); } }
- 在
Program.cs中注册HttpClient时使用这个Handler:
builder.Services.AddHttpClient("ProtectedApi", client => { client.BaseAddress = new Uri("你的API地址"); }).AddHttpMessageHandler<Auth0AuthorizationMessageHandler>();
4. 处理令牌过期与刷新
Access Token有效期较短,需用Refresh Token获取新令牌:
- 通过JS互操作调用Auth0的刷新令牌接口:
// wwwroot/js/auth0.js async function refreshToken(refreshToken) { const response = await fetch('https://你的Auth0域名/oauth/token', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ grant_type: 'refresh_token', client_id: '你的Auth0客户端ID', refresh_token: refreshToken }) }); return await response.json(); }
- 在Blazor中调用这个JS方法,更新存储的令牌并通知认证状态变更:
@inject IJSRuntime JSRuntime @inject ProtectedLocalStorage ProtectedLocalStorage @inject Auth0AuthenticationStateProvider AuthStateProvider public async Task RefreshTokens() { var refreshTokenResult = await ProtectedLocalStorage.GetAsync<string>("auth0_refresh_token"); if (refreshTokenResult.Success && !string.IsNullOrEmpty(refreshTokenResult.Value)) { var newTokens = await JSRuntime.InvokeAsync<Auth0Tokens>("refreshToken", refreshTokenResult.Value); if (!string.IsNullOrEmpty(newTokens.AccessToken)) { await ProtectedLocalStorage.SetAsync("auth0_access_token", newTokens.AccessToken); if (!string.IsNullOrEmpty(newTokens.IdToken)) { await ProtectedLocalStorage.SetAsync("auth0_id_token", newTokens.IdToken); } await AuthStateProvider.NotifyUserAuthenticated(); } } } // 定义令牌模型 public class Auth0Tokens { public string AccessToken { get; set; } public string IdToken { get; set; } public string RefreshToken { get; set; } }
可以在页面初始化时检查Access Token是否即将过期,自动触发刷新。
5. 用户注销流程
注销时需清除本地令牌并通知Auth0结束会话:
- JS互操作实现Auth0注销:
// wwwroot/js/auth0.js function logout() { window.location.href = 'https://你的Auth0域名/v2/logout?client_id=你的Auth0客户端ID&returnTo=你的Blazor网站地址'; }
- Blazor中处理注销:
@inject ProtectedLocalStorage ProtectedLocalStorage @inject Auth0AuthenticationStateProvider AuthStateProvider @inject IJSRuntime JSRuntime public async Task Logout() { // 清除本地存储的令牌 await ProtectedLocalStorage.DeleteAsync("auth0_access_token"); await ProtectedLocalStorage.DeleteAsync("auth0_id_token"); await ProtectedLocalStorage.DeleteAsync("auth0_refresh_token"); // 通知认证状态变更 AuthStateProvider.NotifyUserLogout(); // 调用Auth0注销接口 await JSRuntime.InvokeVoidAsync("logout"); }
内容的提问来源于stack exchange,提问作者Airn5475
相关产品推荐
相关产品推荐

