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

Blazor WASM新浏览器标签页打开时的授权策略问题

Blazor WASM 新窗口授权异常问题解决方案

问题根源

你的问题核心是认证状态存储的窗口隔离性:

  • 若使用Session Storage存储认证令牌/用户Claims,它是单窗口隔离的,新窗口无法读取原有窗口的Session Storage数据,导致AuthenticationStateProvider只能构造出空Claims的已认证用户。
  • 若使用Cookie认证,可能是Cookie的SameSite属性设置为Strict,导致新窗口跳转时不携带Cookie;或是未设置持久化,Cookie仅在当前会话窗口有效。

可行解决方案

1. 切换认证存储到Local Storage

Local Storage是浏览器全局共享的(同域下),可直接跨窗口读取认证信息。

  • 自定义AuthenticationStateProvider,从Local Storage读取用户Claims:
public class CustomAuthStateProvider : AuthenticationStateProvider
{
    private readonly IJSRuntime _jsRuntime;

    public CustomAuthStateProvider(IJSRuntime jsRuntime)
    {
        _jsRuntime = jsRuntime;
    }

    public override async Task<AuthenticationState> GetAuthenticationStateAsync()
    {
        var userJson = await _jsRuntime.InvokeAsync<string>("localStorage.getItem", "authUser");
        if (string.IsNullOrEmpty(userJson))
        {
            return new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity()));
        }

        var claims = JsonSerializer.Deserialize<List<Claim>>(userJson);
        var identity = new ClaimsIdentity(claims, "jwt");
        return new AuthenticationState(new ClaimsPrincipal(identity));
    }

    // 登录成功后调用此方法更新状态并写入Local Storage
    public void UpdateAuthenticationState(ClaimsPrincipal user)
    {
        var claims = user.Claims.ToList();
        var userJson = JsonSerializer.Serialize(claims);
        _ = _jsRuntime.InvokeVoidAsync("localStorage.setItem", "authUser", userJson);
        NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(user)));
    }
}
  • 在Program.cs注册自定义Provider:
builder.Services.AddScoped<AuthenticationStateProvider, CustomAuthStateProvider>();

2. 调整Cookie的SameSite与持久化设置

若使用Cookie认证,修改后端Cookie配置确保跨窗口共享:

builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
    .AddCookie(options =>
    {
        // 允许新窗口携带Cookie
        options.Cookie.SameSite = SameSiteMode.Lax;
        // 设置持久化,避免窗口关闭后Cookie失效
        options.Cookie.IsPersistent = true;
        // HTTPS环境下强制使用Secure属性
        options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
    });

替代方案(若上述方法受限)

3. 新窗口传递临时认证令牌

打开新窗口时,通过URL传递短时效的临时令牌(需确保令牌有效期极短,避免安全风险):

  • 原有窗口打开新窗口的代码:
var tempToken = await _httpClient.GetStringAsync("/api/auth/get-temp-token");
var url = $"{NavigationManager.BaseUri}new-page?token={tempToken}";
await _jsRuntime.InvokeVoidAsync("window.open", url, "_blank");
  • 新窗口页面初始化时,读取令牌并重新获取用户Claims:
protected override async Task OnInitializedAsync()
{
    var token = NavigationManager.GetQueryString("token");
    if (!string.IsNullOrEmpty(token))
    {
        var userClaims = await _httpClient.PostFromJsonAsync<List<Claim>>("/api/auth/validate-temp-token", new { Token = token });
        var authStateProvider = (CustomAuthStateProvider)AuthenticationStateProvider;
        authStateProvider.UpdateAuthenticationState(new ClaimsPrincipal(new ClaimsIdentity(userClaims, "temp")));
        // 清除URL中的令牌,避免泄露
        NavigationManager.NavigateTo(NavigationManager.Uri.Split('?')[0], replace: true);
    }
}

4. 用Broadcast Channel同步认证状态

通过浏览器的Broadcast Channel API,在原有窗口更新认证状态时通知所有同域窗口:

  • 原有窗口登录成功后发送广播:
var channel = new BroadcastChannel("auth-sync");
channel.PostMessage(new 
{ 
    Action = "AuthUpdated", 
    Claims = User.Claims.Select(c => new { c.Type, c.Value }).ToList() 
});
channel.Close();
  • 新窗口监听广播并更新状态:
protected override void OnInitialized()
{
    var channel = new BroadcastChannel("auth-sync");
    channel.Onmessage += async (e) =>
    {
        var data = e.Data as dynamic;
        if (data.Action == "AuthUpdated")
        {
            var claims = ((IEnumerable<dynamic>)data.Claims)
                .Select(c => new Claim(c.Type, c.Value));
            var authStateProvider = (CustomAuthStateProvider)AuthenticationStateProvider;
            authStateProvider.UpdateAuthenticationState(new ClaimsPrincipal(new ClaimsIdentity(claims, "broadcast")));
        }
    };
}

内容的提问来源于stack exchange,提问作者achilles

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 01:52:40