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

Blazor Server端:为Controller/Razor Page添加身份验证授权

解决Blazor Server中Controller/Razor Page的身份验证问题

1. 修正中间件顺序

Blazor Server的中间件顺序有严格要求,错误顺序会直接导致认证/授权失效:

  • UseAuthentication() 必须在 UseAuthorization() 之前
  • 认证、授权中间件必须放在 MapBlazorHub() 和 MapFallbackToPage() 之前
  • 最后映射Controller和Razor Page的路由

示例代码(Program.cs):

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

// 先执行认证,再执行授权
app.UseAuthentication();
app.UseAuthorization();

// Blazor核心路由配置
app.MapBlazorHub();
app.MapFallbackToPage("/_Host");

// 映射Controller和Razor Page路由
app.MapControllers();
app.MapRazorPages();

2. 配置默认认证方案

在服务注册阶段,明确指定默认认证方案为Cookie(与Blazor Server的默认认证体系对齐),同时配置登录跳转路径:

builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
    .AddCookie(options =>
    {
        options.LoginPath = "/Login"; // 和Blazor组件中的登录页路由保持一致
        options.AccessDeniedPath = "/AccessDenied";
        // 可选:配置Cookie过期时间、SameSite属性等参数
    });

// 注册授权服务
builder.Services.AddAuthorization();

3. 同步自定义AuthenticationStateProvider与Cookie认证

自定义的AuthenticationStateProvider必须和Cookie认证同步,才能让Controller/Razor Page识别用户身份:

  • 先注册IHttpContextAccessor用于操作Cookie:
builder.Services.AddHttpContextAccessor();
  • 在自定义Provider中,基于Cookie的ClaimsPrincipal生成认证状态,同时在登录/登出时同步更新Cookie和Blazor组件状态:
public class CustomAuthenticationStateProvider : AuthenticationStateProvider
{
    private readonly IHttpContextAccessor _httpContextAccessor;

    public CustomAuthenticationStateProvider(IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor;
    }

    public override async Task<AuthenticationState> GetAuthenticationStateAsync()
    {
        // 从HttpContext获取Cookie中的用户身份信息
        var principal = _httpContextAccessor.HttpContext?.User ?? new ClaimsPrincipal();
        return await Task.FromResult(new AuthenticationState(principal));
    }

    public async Task Login(string username)
    {
        var claims = new List<Claim> { new Claim(ClaimTypes.Name, username) };
        var identity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
        var principal = new ClaimsPrincipal(identity);

        // 写入登录Cookie,供Controller/Razor Page识别
        await _httpContextAccessor.HttpContext.SignInAsync(
            CookieAuthenticationDefaults.AuthenticationScheme, 
            principal);

        // 通知Blazor组件更新认证状态
        NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(principal)));
    }

    public async Task Logout()
    {
        // 清除登录Cookie
        await _httpContextAccessor.HttpContext.SignOutAsync(
            CookieAuthenticationDefaults.AuthenticationScheme);

        // 通知Blazor组件更新状态
        NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(new ClaimsPrincipal())));
    }
}

4. 为Controller/Razor Page添加[Authorize]特性

完成以上配置后,直接在Controller或Razor Page的类/方法上添加[Authorize]特性即可,未认证用户访问时会自动跳转到配置的登录页:

[Authorize]
public class DownloadController : Controller
{
    public IActionResult GetFile()
    {
        // 仅认证用户可访问此方法
        return File("wwwroot/files/sample.pdf", "application/pdf", "sample.pdf");
    }
}

关键注意事项

  • 自定义AuthenticationStateProvider不能单独维护内存中的用户信息,必须基于Cookie的ClaimsPrincipal生成认证状态,否则Controller无法识别用户身份。
  • 中间件顺序绝对不能颠倒,否则会出现「缺少授权中间件」或认证不生效的异常。
  • 确保LoginPath配置的路由和Blazor组件中的登录页一致,避免跳转冲突。

内容的提问来源于stack exchange,提问作者Mike T. Angelo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 12:50:23