You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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的认证系统使用:

  1. 先引入System.IdentityModel.Tokens.Jwt NuGet包
  2. 编写解析方法:
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"));
}
  1. 自定义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:

  1. 自定义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);
    }
}
  1. 在Program.cs中注册HttpClient时使用这个Handler:
builder.Services.AddHttpClient("ProtectedApi", client =>
{
    client.BaseAddress = new Uri("你的API地址");
}).AddHttpMessageHandler<Auth0AuthorizationMessageHandler>();

4. 处理令牌过期与刷新

Access Token有效期较短,需用Refresh Token获取新令牌:

  1. 通过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();
}
  1. 在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结束会话:

  1. JS互操作实现Auth0注销:
// wwwroot/js/auth0.js
function logout() {
    window.location.href = 'https://你的Auth0域名/v2/logout?client_id=你的Auth0客户端ID&returnTo=你的Blazor网站地址';
}
  1. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 19:15:57