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

使用带独立认证的Blazor模板时,如何自定义认证状态提供程序?

在带独立认证的Blazor项目中添加自定义状态逻辑(不破坏原有Identity功能)

以下是一套不改动原有Identity核心功能的实现方案,专注于扩展自定义状态数据的获取、更新与UI刷新:

1. 创建Scoped级别的自定义状态服务

先做一个与用户会话绑定的状态服务,用来封装所有自定义业务数据和操作逻辑,避免直接在组件里写业务代码:

public class AppStateService : IDisposable
{
    private readonly AuthenticationStateProvider _authStateProvider;
    public event Action? StateChanged;

    // 自定义状态数据示例
    public UserProfile? CurrentProfile { get; private set; }
    public UserSettings? UserSettings { get; private set; }

    public AppStateService(AuthenticationStateProvider authStateProvider)
    {
        _authStateProvider = authStateProvider;
        // 监听登录/注销事件,自动同步状态
        _authStateProvider.AuthenticationStateChanged += OnAuthStateChanged;
    }

    private async void OnAuthStateChanged(Task<AuthenticationState> authStateTask)
    {
        var authState = await authStateTask;
        await LoadUserState(authState.User);
    }

    // 初始化/刷新用户自定义状态
    public async Task LoadUserState(ClaimsPrincipal user)
    {
        if (!user.Identity?.IsAuthenticated ?? false)
        {
            // 用户未登录时清空状态
            CurrentProfile = null;
            UserSettings = null;
            NotifyStateChanged();
            return;
        }

        // 从业务API/数据库加载自定义数据(替换成你的实际逻辑)
        var userId = user.FindFirstValue(ClaimTypes.NameIdentifier);
        if (!string.IsNullOrEmpty(userId))
        {
            // 示例:调用后端接口获取数据
            // CurrentProfile = await _httpClient.GetFromJsonAsync<UserProfile>($"api/users/{userId}/profile");
            // UserSettings = await _httpClient.GetFromJsonAsync<UserSettings>($"api/users/{userId}/settings");
            
            // 模拟数据
            CurrentProfile = new UserProfile { Id = userId, Nickname = user.Identity.Name, Bio = "个人简介" };
            UserSettings = new UserSettings { Theme = "Light", AllowNotifications = true };
        }

        NotifyStateChanged();
    }

    // 更新用户设置的示例方法
    public async Task UpdateUserSettings(UserSettings newSettings)
    {
        if (CurrentProfile == null) return;

        // 先调用后端API保存数据(替换成你的实际接口)
        // await _httpClient.PutAsJsonAsync($"api/users/{CurrentProfile.Id}/settings", newSettings);
        
        // 更新本地状态并通知组件刷新
        UserSettings = newSettings;
        NotifyStateChanged();
    }

    private void NotifyStateChanged() => StateChanged?.Invoke();

    public void Dispose()
    {
        _authStateProvider.AuthenticationStateChanged -= OnAuthStateChanged;
    }

    // 自定义数据模型
    public class UserProfile
    {
        public string Id { get; set; } = string.Empty;
        public string Nickname { get; set; } = string.Empty;
        public string Bio { get; set; } = string.Empty;
    }

    public class UserSettings
    {
        public string Theme { get; set; } = string.Empty;
        public bool AllowNotifications { get; set; }
    }
}

2. 注册状态服务到DI容器

在Program.cs中添加服务注册,保持Scoped生命周期(和用户会话一致):

builder.Services.AddScoped<AppStateService>();

3. 在组件中使用自定义状态

以用户设置组件为例,展示如何绑定数据、更新状态并自动刷新UI:

@inject AppStateService AppState
@implements IAsyncDisposable

<h2>我的设置</h2>

@if (AppState.CurrentProfile == null)
{
    <p>请先登录</p>
}
else
{
    <div>
        <label>主题:</label>
        <select @bind="_selectedTheme">
            <option value="Light">浅色</option>
            <option value="Dark">深色</option>
        </select>
    </div>
    <div>
        <label>
            <input type="checkbox" @bind="_allowNotifications" />
            允许推送通知
        </label>
    </div>
    <button @onclick="SaveSettings">保存设置</button>
}

@code {
    private string _selectedTheme = string.Empty;
    private bool _allowNotifications;

    protected override async Task OnInitializedAsync()
    {
        // 初始化时加载状态
        var authState = await AppState._authStateProvider.GetAuthenticationStateAsync();
        await AppState.LoadUserState(authState.User);
        
        // 订阅状态变化事件,自动刷新UI
        AppState.StateChanged += OnStateUpdated;
        
        // 初始化表单值
        if (AppState.UserSettings != null)
        {
            _selectedTheme = AppState.UserSettings.Theme;
            _allowNotifications = AppState.UserSettings.AllowNotifications;
        }
    }

    private void OnStateUpdated()
    {
        // 状态变化时强制组件重新渲染
        InvokeAsync(StateHasChanged);
    }

    private async Task SaveSettings()
    {
        var newSettings = new AppStateService.UserSettings
        {
            Theme = _selectedTheme,
            AllowNotifications = _allowNotifications
        };
        await AppState.UpdateUserSettings(newSettings);
    }

    // 组件销毁时取消事件订阅,避免内存泄漏
    public async ValueTask DisposeAsync()
    {
        AppState.StateChanged -= OnStateUpdated;
    }
}

关键注意事项

  • 完全复用原有Identity认证体系:仅依赖AuthenticationStateProvider获取用户状态,不修改任何Identity核心服务,原有登录/注销、权限验证功能不受影响。
  • 状态隔离:Scoped服务确保每个用户的自定义数据相互独立,不会出现数据混叠。
  • 自动同步:通过监听AuthenticationStateChanged事件,实现登录后自动加载状态、注销后清空状态的逻辑。
  • UI刷新机制:利用StateChanged事件统一通知组件刷新,避免在每个操作后手动调用StateHasChanged。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 13:13:13