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

Blazor Server自定义认证:登录后授权访问<Authorized>标签内容

Blazor Server自定义登录与授权实现

要实现自定义登录并让用户访问<Authorized>标签内容,核心是通过**自定义AuthenticationStateProvider**管理用户认证状态,结合登录服务完成API验证与状态更新,具体步骤如下:

1. 实现自定义AuthenticationStateProvider

创建继承自AuthenticationStateProvider的类,负责维护当前用户的认证状态,并提供状态更新的方法:

using Microsoft.AspNetCore.Components.Authorization;
using System.Security.Claims;

namespace AdminFrontend.Services
{
    public class CustomAuthStateProvider : AuthenticationStateProvider
    {
        // 存储当前认证用户的ClaimsPrincipal
        private ClaimsPrincipal _currentUser = new ClaimsPrincipal(new ClaimsIdentity());

        // 返回当前认证状态
        public override Task<AuthenticationState> GetAuthenticationStateAsync()
        {
            return Task.FromResult(new AuthenticationState(_currentUser));
        }

        // 登录成功后更新用户状态
        public void UpdateAuthenticationState(User user, List<string>? roles = null)
        {
            // 创建用户身份标识,添加邮箱、手机号等声明
            var claims = new List<Claim>
            {
                new Claim(ClaimTypes.Email, user.email),
                new Claim(ClaimTypes.MobilePhone, user.mobilenumber)
            };

            // 若有角色,添加角色声明
            if (roles != null)
            {
                claims.AddRange(roles.Select(r => new Claim(ClaimTypes.Role, r)));
            }

            var identity = new ClaimsIdentity(claims, "CustomAuth");
            _currentUser = new ClaimsPrincipal(identity);

            // 通知Blazor框架状态变更,触发页面重新授权检查
            NotifyAuthenticationStateChanged(GetAuthenticationStateAsync());
        }

        // 登出时重置状态
        public void Logout()
        {
            _currentUser = new ClaimsPrincipal(new ClaimsIdentity());
            NotifyAuthenticationStateChanged(GetAuthenticationStateAsync());
        }
    }
}

2. 创建登录服务封装API验证逻辑

编写登录服务,负责调用后端API验证用户信息,返回验证结果并更新认证状态:

using System.Net.Http.Json;

namespace AdminFrontend.Services
{
    public class AuthService
    {
        private readonly HttpClient _httpClient;
        private readonly CustomAuthStateProvider _authStateProvider;

        public AuthService(HttpClient httpClient, CustomAuthStateProvider authStateProvider)
        {
            _httpClient = httpClient;
            _authStateProvider = authStateProvider;
        }

        // 调用API验证登录,成功则更新认证状态
        public async Task<bool> Login(User user)
        {
            try
            {
                // 调用后端登录API,假设返回包含用户角色的响应
                var response = await _httpClient.PostAsJsonAsync("api/auth/login", user);
                
                if (response.IsSuccessStatusCode)
                {
                    // 从API响应获取用户角色(根据实际接口调整)
                    var loginResult = await response.Content.ReadFromJsonAsync<LoginResponse>();
                    
                    // 更新认证状态
                    _authStateProvider.UpdateAuthenticationState(user, loginResult?.Roles);
                    return true;
                }
                return false;
            }
            catch
            {
                return false;
            }
        }

        // 登出方法
        public void Logout()
        {
            _authStateProvider.Logout();
        }
    }

    // 适配API返回的登录结果模型(根据实际接口调整)
    public class LoginResponse
    {
        public List<string>? Roles { get; set; }
        // 可添加令牌、用户ID等其他字段
    }
}

3. 在Program.cs中注册服务

将自定义的认证状态提供者和登录服务注入到依赖容器:

using AdminFrontend.Services;
using Microsoft.AspNetCore.Components.Authorization;

var builder = WebApplication.CreateBuilder(args);

// 添加Blazor组件服务
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();

// 注册HttpClient
builder.Services.AddHttpClient();

// 注册自定义认证状态提供者和登录服务
builder.Services.AddScoped<AuthenticationStateProvider, CustomAuthStateProvider>();
builder.Services.AddScoped<AuthService>();

var app = builder.Build();

// ... 中间件配置省略 ...

app.Run();

4. 登录组件实现逻辑

在自定义登录表单组件中,调用AuthService完成登录,成功后跳转页面:

@page "/login"
@inject AuthService AuthService
@inject NavigationManager NavManager

<h3>登录</h3>

<div>
    <input type="email" @bind="@user.email" placeholder="邮箱" />
    <input type="password" @bind="@user.password" placeholder="密码" />
    <input type="text" @bind="@user.mobilenumber" placeholder="手机号" />
    <input type="text" @bind="@user.service" placeholder="服务标识" />
    <button @onclick="HandleLogin">登录</button>
</div>

@code {
    private User user = new User();

    private async Task HandleLogin()
    {
        bool loginSuccess = await AuthService.Login(user);
        if (loginSuccess)
        {
            // 登录成功后跳转至主页或指定页面
            NavManager.NavigateTo("/");
        }
        else
        {
            // 登录失败提示
            Console.WriteLine("登录失败,请检查账号密码");
        }
    }
}

5. 导航菜单与授权控制

使用<AuthorizeView>组件控制导航菜单的显示,登录后自动切换菜单内容:

<NavMenu>
    <AuthorizeView>
        <Authorized>
            <div class="nav-item px-3">
                <NavLink class="nav-link" href="/dashboard">
                    <span class="oi oi-dashboard" aria-hidden="true"></span> 控制台
                </NavLink>
            </div>
            <div class="nav-item px-3">
                <button class="nav-link" @onclick="() => AuthService.Logout()">
                    <span class="oi oi-account-logout" aria-hidden="true"></span> 登出
                </button>
            </div>
        </Authorized>
        <NotAuthorized>
            <div class="nav-item px-3">
                <NavLink class="nav-link" href="/login">
                    <span class="oi oi-account-login" aria-hidden="true"></span> 登录
                </NavLink>
            </div>
        </NotAuthorized>
    </AuthorizeView>
</NavMenu>

@code {
    [Inject]
    private AuthService AuthService { get; set; }
}

6. 保护页面内容

在需要授权的页面或组件中,使用<Authorize>标签或<AuthorizeView>保护内容:

@page "/dashboard"
@attribute [Authorize]

<h1>控制台</h1>
<p>仅登录用户可查看此内容</p>

关键说明

  • CustomAuthStateProvider通过NotifyAuthenticationStateChanged方法通知框架状态变更,触发页面重新进行授权检查,从而自动更新<Authorized>和<NotAuthorized>区域的内容。
  • 如果API返回JWT令牌,可将令牌存储在LocalStorage或SessionStorage中,在CustomAuthStateProvider初始化时读取令牌并恢复用户状态(适合持久化登录场景)。
  • 角色授权可通过[Authorize(Roles = "Admin")]属性实现,只需在UpdateAuthenticationState中添加对应的角色声明即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 18:31:06