Blazor怎么集成JWT认证

来源:个人站长作者:三上悠亚头衔:网络博主
导读:本期聚焦于小伙伴创作的《Blazor怎么集成JWT认证》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《Blazor怎么集成JWT认证》有用,将其分享出去将是对创作者最好的鼓励。

Blazor应用集成JWT认证需要同时处理后端API的Token生成逻辑和前端应用的认证状态管理,整体分为服务端配置、前端Token处理、认证状态同步三个核心环节。

Blazor怎么集成JWT认证

一、后端ASP.NET Core API配置JWT生成

首先需要在后端项目中安装JWT相关的NuGet包,然后配置认证服务与Token生成逻辑。

1. 安装依赖包

在ASP.NET Core项目中执行以下命令安装所需包:

Install-Package Microsoft.AspNetCore.Authentication.JwtBearer
Install-Package System.IdentityModel.Tokens.Jwt

2. 配置JWT服务

在Program.cs中添加JWT认证服务配置,设置密钥、发行者、受众等参数:

using Microsoft.IdentityModel.Tokens;
using System.Text;

var builder = WebApplication.CreateBuilder(args);

// 配置JWT参数
var jwtSettings = builder.Configuration.GetSection("JwtSettings");
var key = Encoding.ASCII.GetBytes(jwtSettings["Key"]);

builder.Services.AddAuthentication(options =>
{
    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
    options.TokenValidationParameters = new TokenValidationParameters
    {
        ValidateIssuerSigningKey = true,
        IssuerSigningKey = new SymmetricSecurityKey(key),
        ValidateIssuer = true,
        ValidIssuer = jwtSettings["Issuer"],
        ValidateAudience = true,
        ValidAudience = jwtSettings["Audience"],
        ValidateLifetime = true,
        ClockSkew = TimeSpan.Zero
    };
});

builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

// 启用认证中间件
app.UseAuthentication();
app.UseAuthorization();

app.MapControllers();
app.Run();

3. 实现登录接口生成Token

创建登录接口,验证用户凭证后生成JWT Token返回给前端:

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;

[ApiController]
[Route("api/[controller]")]
public class AuthController : ControllerBase
{
    private readonly IConfiguration _configuration;

    public AuthController(IConfiguration configuration)
    {
        _configuration = configuration;
    }

    [HttpPost("login")]
    [AllowAnonymous]
    public IActionResult Login([FromBody] LoginRequest request)
    {
        // 这里替换为实际的用户验证逻辑
        if (request.Username == "admin" && request.Password == "123456")
        {
            var jwtSettings = _configuration.GetSection("JwtSettings");
            var key = Encoding.ASCII.GetBytes(jwtSettings["Key"]);
            var tokenHandler = new JwtSecurityTokenHandler();
            var tokenDescriptor = new SecurityTokenDescriptor
            {
                Subject = new ClaimsIdentity(new Claim[]
                {
                    new Claim(ClaimTypes.Name, request.Username),
                    new Claim(ClaimTypes.Role, "Admin")
                }),
                Expires = DateTime.UtcNow.AddHours(2),
                Issuer = jwtSettings["Issuer"],
                Audience = jwtSettings["Audience"],
                SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithm.HmacSha256Signature)
            };
            var token = tokenHandler.CreateToken(tokenDescriptor);
            var tokenString = tokenHandler.WriteToken(token);
            return Ok(new { Token = tokenString });
        }
        return Unauthorized("用户名或密码错误");
    }
}

public class LoginRequest
{
    public string Username { get; set; }
    public string Password { get; set; }
}

同时在appsettings.json中添加JWT配置:

{
  "JwtSettings": {
    "Key": "YourSuperSecretKeyHere1234567890",
    "Issuer": "BlazorDemo",
    "Audience": "BlazorClient"
  }
}

二、Blazor前端处理JWT Token

Blazor应用需要存储后端返回的Token,并在后续请求中携带Token完成认证。

1. 创建Token存储服务

创建专门的服务用于管理Token的本地存储与读取,这里使用浏览器的localStorage存储Token:

using Microsoft.JSInterop;

public class TokenService
{
    private readonly IJSRuntime _jsRuntime;

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

    public async Task SaveTokenAsync(string token)
    {
        await _jsRuntime.InvokeVoidAsync("localStorage.setItem", "jwt_token", token);
    }

    public async Task<string> GetTokenAsync()
    {
        return await _jsRuntime.InvokeAsync<string>("localStorage.getItem", "jwt_token");
    }

    public async Task RemoveTokenAsync()
    {
        await _jsRuntime.InvokeVoidAsync("localStorage.removeItem", "jwt_token");
    }
}

2. 封装带Token的HTTP请求

创建自定义的HttpMessageHandler,在发送请求时自动添加Authorization请求头:

using System.Net.Http.Headers;

public class AuthHeaderHandler : DelegatingHandler
{
    private readonly TokenService _tokenService;

    public AuthHeaderHandler(TokenService tokenService)
    {
        _tokenService = tokenService;
    }

    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var token = await _tokenService.GetTokenAsync();
        if (!string.IsNullOrEmpty(token))
        {
            request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
        }
        return await base.SendAsync(request, cancellationToken);
    }
}

在Program.cs中注册相关服务:

using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;

var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");
builder.RootComponents.Add<HeadOutlet>("head::after");

// 注册Token服务
builder.Services.AddScoped<TokenService>();

// 注册带认证头的HttpClient
builder.Services.AddScoped<AuthHeaderHandler>();
builder.Services.AddScoped(sp =>
{
    var handler = sp.GetRequiredService<AuthHeaderHandler>();
    handler.InnerHandler = new HttpClientHandler();
    return new HttpClient(handler)
    {
        BaseAddress = new Uri("http://localhost:5000/")
    };
});

await builder.Build().RunAsync();

三、Blazor认证状态管理

需要实现自定义的AuthenticationStateProvider,让Blazor能够识别用户的认证状态。

1. 自定义认证状态提供器

using System.Security.Claims;

public class JwtAuthenticationStateProvider : AuthenticationStateProvider
{
    private readonly TokenService _tokenService;

    public JwtAuthenticationStateProvider(TokenService tokenService)
    {
        _tokenService = tokenService;
    }

    public override async Task<AuthenticationState> GetAuthenticationStateAsync()
    {
        var token = await _tokenService.GetTokenAsync();
        if (string.IsNullOrEmpty(token))
        {
            return new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity()));
        }
        // 这里简单解析Token,实际项目可以验证Token有效性
        var claims = new List<Claim>
        {
            new Claim(ClaimTypes.Name, "当前用户")
        };
        var identity = new ClaimsIdentity(claims, "jwt");
        var user = new ClaimsPrincipal(identity);
        return new AuthenticationState(user);
    }

    public void NotifyUserAuthentication(string token)
    {
        var claims = new List<Claim>
        {
            new Claim(ClaimTypes.Name, "当前用户")
        };
        var identity = new ClaimsIdentity(claims, "jwt");
        var user = new ClaimsPrincipal(identity);
        var authState = Task.FromResult(new AuthenticationState(user));
        NotifyAuthenticationStateChanged(authState);
    }

    public void NotifyUserLogout()
    {
        var authState = Task.FromResult(new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity())));
        NotifyAuthenticationStateChanged(authState);
    }
}

在Program.cs中注册该服务:

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

2. 实现登录与登出逻辑

创建登录页面,调用后端登录接口存储Token并更新认证状态:

@page "/login"
@inject TokenService TokenService
@inject JwtAuthenticationStateProvider AuthStateProvider
@inject HttpClient Http
@inject NavigationManager Navigation

<h3>用户登录</h3>
<EditForm Model="@loginRequest" OnValidSubmit="HandleLogin">
    <DataAnnotationsValidator />
    <ValidationSummary />
    <div class="mb-3">
        <label>用户名</label>
        <InputText class="form-control" @bind-Value="loginRequest.Username" />
    </div>
    <div class="mb-3">
        <label>密码</label>
        <InputText type="password" class="form-control" @bind-Value="loginRequest.Password" />
    </div>
    <button type="submit" class="btn btn-primary">登录</button>
</EditForm>

@code {
    private LoginRequest loginRequest = new();

    private async Task HandleLogin()
    {
        var response = await Http.PostAsJsonAsync("api/auth/login", loginRequest);
        if (response.IsSuccessStatusCode)
        {
            var result = await response.Content.ReadFromJsonAsync<LoginResult>();
            await TokenService.SaveTokenAsync(result.Token);
            AuthStateProvider.NotifyUserAuthentication(result.Token);
            Navigation.NavigateTo("/");
        }
        else
        {
            // 处理登录失败逻辑
        }
    }

    public class LoginResult
    {
        public string Token { get; set; }
    }
}

登出逻辑只需要清除本地Token并更新认证状态:

private async Task HandleLogout()
{
    await TokenService.RemoveTokenAsync();
    AuthStateProvider.NotifyUserLogout();
    Navigation.NavigateTo("/login");
}

四、路由权限控制

使用Blazor内置的<AuthorizeRouteView>和<AuthorizeView>组件实现路由和页面元素的权限控制。

在App.razor中修改路由配置:

<Router AppAssembly="@typeof(App).Assembly">
    <Found Context="routeData">
        <AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)">
            <NotAuthorized>
                <p>你没有权限访问该页面,请先<a href="/login">登录</a>。</p>
            </NotAuthorized>
            <Authorizing>
                <p>正在验证身份...</p>
            </Authorizing>
        </AuthorizeRouteView>
    </Found>
    <NotFound>
        <LayoutView Layout="@typeof(MainLayout)">
            <p>抱歉,找不到你请求的页面。</p>
        </LayoutView>
    </NotFound>
</Router>

在需要权限控制的页面上添加<Authorize>特性:

@page "/admin"
@attribute [Authorize(Roles = "Admin")]

<h3>管理员页面</h3>
<p>只有管理员角色可以访问该页面</p>

也可以在页面内部使用<AuthorizeView>组件控制元素显示:

<AuthorizeView Roles="Admin">
    <Authorized>
        <p>管理员可见内容</p>
    </Authorized>
    <NotAuthorized>
        <p>你不是管理员,无法查看该内容</p>
    </NotAuthorized>
</AuthorizeView>

BlazorJWT认证ASP.NET_Core身份认证Token验证修改时间:2026-07-10 19:18:46

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。