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

.NET 8身份验证API能否用于Blazor?及后续实现方法

问题解答

可行性说明

完全可行,你可以通过自定义登录流程,将用户名密码发送到自己搭建的.NET 8身份验证API获取JWT令牌,之后在Blazor应用中管理令牌并实现身份验证逻辑,无需依赖脚手架生成的Area/Identity页面。

Blazor Server 实现流程

1. 自定义身份状态管理

创建自定义AuthenticationStateProvider来管理令牌和用户身份,推荐结合Blazored.LocalStorage存储令牌(需安装对应NuGet包):

public class CustomAuthStateProvider : AuthenticationStateProvider
{
    private readonly HttpClient _httpClient;
    private readonly ILocalStorageService _localStorage;

    public CustomAuthStateProvider(HttpClient httpClient, ILocalStorageService localStorage)
    {
        _httpClient = httpClient;
        _localStorage = localStorage;
    }

    public override async Task<AuthenticationState> GetAuthenticationStateAsync()
    {
        var token = await _localStorage.GetItemAsync<string>("authToken");
        var identity = new ClaimsIdentity();

        if (!string.IsNullOrEmpty(token))
        {
            var claims = ParseClaimsFromJwt(token);
            identity = new ClaimsIdentity(claims, "jwt");
        }

        var user = new ClaimsPrincipal(identity);
        return new AuthenticationState(user);
    }

    public async Task LoginAsync(string token)
    {
        await _localStorage.SetItemAsync("authToken", token);
        NotifyAuthenticationStateChanged(GetAuthenticationStateAsync());
    }

    public async Task LogoutAsync()
    {
        await _localStorage.RemoveItemAsync("authToken");
        NotifyAuthenticationStateChanged(GetAuthenticationStateAsync());
    }

    private IEnumerable<Claim> ParseClaimsFromJwt(string jwt)
    {
        var payload = jwt.Split('.')[1];
        var jsonBytes = ParseBase64WithoutPadding(payload);
        var keyValuePairs = JsonSerializer.Deserialize<Dictionary<string, object>>(jsonBytes);
        return keyValuePairs.Select(kvp => new Claim(kvp.Key, kvp.Value.ToString()));
    }

    private byte[] ParseBase64WithoutPadding(string base64)
    {
        switch (base64.Length % 4)
        {
            case 2: base64 += "=="; break;
            case 3: base64 += "="; break;
        }
        return Convert.FromBase64String(base64);
    }
}

2. 自定义登录页面逻辑

在自己的登录Blazor页面中,调用API获取令牌并触发身份状态更新:

@page "/login"
@inject HttpClient Http
@inject CustomAuthStateProvider AuthStateProvider
@inject NavigationManager NavManager

<div class="login-form">
    <input @bind="Username" placeholder="用户名" class="form-input" />
    <input @bind="Password" type="password" placeholder="密码" class="form-input" />
    <button @onclick="HandleLogin" class="login-btn">登录</button>
    @if (!string.IsNullOrEmpty(ErrorMessage))
    {
        <p class="error-message">@ErrorMessage</p>
    }
</div>

@code {
    private string Username { get; set; }
    private string Password { get; set; }
    private string ErrorMessage { get; set; }

    private async Task HandleLogin()
    {
        ErrorMessage = string.Empty;
        var loginRequest = new { Username = Username, Password = Password };
        var response = await Http.PostAsJsonAsync("/api/auth/login", loginRequest);
        
        if (response.IsSuccessStatusCode)
        {
            var tokenResponse = await response.Content.ReadFromJsonAsync<TokenResponse>();
            await AuthStateProvider.LoginAsync(tokenResponse.AccessToken);
            NavManager.NavigateTo("/");
        }
        else
        {
            ErrorMessage = "用户名或密码错误";
        }
    }

    private class TokenResponse
    {
        public string AccessToken { get; set; }
    }
}

3. 配置服务与路由保护

在Program.cs中注册自定义服务:

builder.Services.AddScoped<AuthenticationStateProvider, CustomAuthStateProvider>();
builder.Services.AddBlazoredLocalStorage();
builder.Services.AddAuthorizationCore();

使用AuthorizeRouteView保护需要登录的页面:

<Router AppAssembly="@typeof(App).Assembly">
    <Found Context="routeData">
        <AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)">
            <NotAuthorized>
                <RedirectToLogin />
            </NotAuthorized>
        </AuthorizeRouteView>
    </Found>
    <NotFound>
        <LayoutView Layout="@typeof(MainLayout)">
            <p>抱歉,该页面不存在</p>
        </LayoutView>
    </NotFound>
</Router>

Blazor Hybrid(MAUI Blazor)实现流程

流程与Blazor Server类似,主要差异在于令牌存储方式,改用MAUI内置的Preferences或SecureStorage:

1. 调整身份状态管理

public class HybridAuthStateProvider : AuthenticationStateProvider
{
    private readonly HttpClient _httpClient;

    public HybridAuthStateProvider(HttpClient httpClient)
    {
        _httpClient = httpClient;
    }

    public override async Task<AuthenticationState> GetAuthenticationStateAsync()
    {
        var token = SecureStorage.GetAsync("authToken").Result;
        var identity = new ClaimsIdentity();

        if (!string.IsNullOrEmpty(token))
        {
            var claims = ParseClaimsFromJwt(token);
            identity = new ClaimsIdentity(claims, "jwt");
        }

        var user = new ClaimsPrincipal(identity);
        return new AuthenticationState(user);
    }

    public async Task LoginAsync(string token)
    {
        await SecureStorage.SetAsync("authToken", token);
        NotifyAuthenticationStateChanged(GetAuthenticationStateAsync());
    }

    public async Task LogoutAsync()
    {
        await SecureStorage.RemoveAsync("authToken");
        NotifyAuthenticationStateChanged(GetAuthenticationStateAsync());
    }

    // 复用ParseClaimsFromJwt和ParseBase64WithoutPadding方法
}

2. 配置服务

builder.Services.AddScoped<AuthenticationStateProvider, HybridAuthStateProvider>();
builder.Services.AddAuthorizationCore();

关键注意事项

  • 令牌过期处理:API返回令牌时携带过期时间,在Blazor中定时检查,过期后自动跳转登录页。
  • 请求自动携带令牌:创建DelegatingHandler拦截HTTP请求,自动添加Authorization: Bearer {token}头,避免每个请求手动设置。
  • 安全存储:Blazor Hybrid中优先使用SecureStorage存储令牌,避免明文存储敏感数据。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 08:18:15