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

求助:Blazor Server项目基于Microsoft Identity实现授权与角色用户管理

Blazor Server + Microsoft Identity 角色与用户管理实现方案

一、基础配置(未完成的话先做这步)

首先确保项目引入必要依赖并配置Identity:

  1. 安装NuGet包:
    Install-Package Microsoft.AspNetCore.Identity.EntityFrameworkCore
    Install-Package Microsoft.EntityFrameworkCore.SqlServer
    
  2. 修改你的DbContext,继承带角色支持的Identity上下文:
    public class AppDbContext : IdentityDbContext<IdentityUser, IdentityRole, string>
    {
        public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }
    }
    
  3. 在Program.cs中配置Identity与数据库:
    var builder = WebApplication.CreateBuilder(args);
    
    // 配置DbContext
    builder.Services.AddDbContext<AppDbContext>(options =>
        options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));
    
    // 添加Identity并启用角色支持
    builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
        .AddRoles<IdentityRole>()
        .AddEntityFrameworkStores<AppDbContext>();
    
    // 添加Blazor与Razor Pages支持(Identity需要Razor Pages处理登录等页面)
    builder.Services.AddRazorPages();
    builder.Services.AddServerSideBlazor();
    
    var app = builder.Build();
    
    // 中间件配置
    if (!app.Environment.IsDevelopment())
    {
        app.UseExceptionHandler("/Error");
        app.UseHsts();
    }
    
    app.UseHttpsRedirection();
    app.UseStaticFiles();
    app.UseRouting();
    
    // Identity认证中间件
    app.UseAuthentication();
    app.UseAuthorization();
    
    app.MapRazorPages(); // 必须添加,否则Identity内置页面无法访问
    app.MapBlazorHub();
    app.MapFallbackToPage("/_Host");
    
    app.Run();
    
  4. 执行数据库迁移:
    打开Package Manager Console,依次运行:
    Add-Migration InitializeIdentity
    Update-Database
    

二、角色管理页面实现

创建RoleManagement.razor组件,实现角色的增删改查:

@inject RoleManager<IdentityRole> RoleManager
@inject ILogger<RoleManagement> Logger
@attribute [Authorize(Roles = "Admin")]

<div class="container mt-4">
    <h3>角色管理</h3>

    <!-- 创建角色表单 -->
    <div class="card mb-3">
        <div class="card-body">
            <h5 class="card-title">创建新角色</h5>
            <div class="input-group">
                <input type="text" class="form-control" placeholder="输入角色名称" @bind="NewRoleName" />
                <button class="btn btn-primary" @onclick="CreateRole">创建</button>
            </div>
        </div>
    </div>

    <!-- 角色列表 -->
    <table class="table table-striped">
        <thead>
            <tr>
                <th>角色名称</th>
                <th>操作</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var role in Roles)
            {
                <tr>
                    <td>@role.Name</td>
                    <td>
                        <button class="btn btn-sm btn-warning" @onclick="() => EditRole(role)">编辑</button>
                        <button class="btn btn-sm btn-danger ms-2" @onclick="() => DeleteRole(role)">删除</button>
                    </td>
                </tr>
            }
        </tbody>
    </table>

    <!-- 编辑角色模态框 -->
    @if (SelectedRole != null)
    {
        <div class="modal show d-block" style="background-color: rgba(0,0,0,0.5)">
            <div class="modal-dialog">
                <div class="modal-content">
                    <div class="modal-header">
                        <h5 class="modal-title">编辑角色</h5>
                        <button type="button" class="btn-close" @onclick="() => SelectedRole = null"></button>
                    </div>
                    <div class="modal-body">
                        <input type="text" class="form-control" @bind="EditedRoleName" />
                    </div>
                    <div class="modal-footer">
                        <button class="btn btn-secondary" @onclick="() => SelectedRole = null">取消</button>
                        <button class="btn btn-primary" @onclick="UpdateRole">保存</button>
                    </div>
                </div>
            </div>
        </div>
    }
</div>

@code {
    private List<IdentityRole> Roles = new();
    private string NewRoleName = string.Empty;
    private IdentityRole? SelectedRole;
    private string EditedRoleName = string.Empty;

    protected override async Task OnInitializedAsync()
    {
        await LoadRoles();
    }

    private async Task LoadRoles()
    {
        Roles = (await RoleManager.Roles.ToListAsync()).OrderBy(r => r.Name).ToList();
        StateHasChanged();
    }

    private async Task CreateRole()
    {
        if (string.IsNullOrWhiteSpace(NewRoleName)) return;

        var result = await RoleManager.CreateAsync(new IdentityRole(NewRoleName.Trim()));
        if (result.Succeeded)
        {
            NewRoleName = string.Empty;
            await LoadRoles();
        }
        else
        {
            foreach (var error in result.Errors)
            {
                Logger.LogError("创建角色失败:{Error}", error.Description);
            }
        }
    }

    private void EditRole(IdentityRole role)
    {
        SelectedRole = role;
        EditedRoleName = role.Name ?? string.Empty;
    }

    private async Task UpdateRole()
    {
        if (SelectedRole == null || string.IsNullOrWhiteSpace(EditedRoleName)) return;

        SelectedRole.Name = EditedRoleName.Trim();
        var result = await RoleManager.UpdateAsync(SelectedRole);
        if (result.Succeeded)
        {
            SelectedRole = null;
            await LoadRoles();
        }
        else
        {
            foreach (var error in result.Errors)
            {
                Logger.LogError("更新角色失败:{Error}", error.Description);
            }
        }
    }

    private async Task DeleteRole(IdentityRole role)
    {
        var result = await RoleManager.DeleteAsync(role);
        if (result.Succeeded)
        {
            await LoadRoles();
        }
        else
        {
            foreach (var error in result.Errors)
            {
                Logger.LogError("删除角色失败:{Error}", error.Description);
            }
        }
    }
}

三、用户管理与角色分配页面

创建UserManagement.razor组件,实现用户的增删改及角色分配:

@inject UserManager<IdentityUser> UserManager
@inject RoleManager<IdentityRole> RoleManager
@inject ILogger<UserManagement> Logger
@attribute [Authorize(Roles = "Admin")]

<div class="container mt-4">
    <h3>用户管理</h3>

    <!-- 创建用户表单 -->
    <div class="card mb-3">
        <div class="card-body">
            <h5 class="card-title">创建新用户</h5>
            <div class="row g-3">
                <div class="col-md-6">
                    <input type="email" class="form-control" placeholder="邮箱" @bind="NewUserEmail" />
                </div>
                <div class="col-md-6">
                    <input type="password" class="form-control" placeholder="密码" @bind="NewUserPassword" />
                </div>
                <div class="col-12">
                    <button class="btn btn-primary" @onclick="CreateUser">创建</button>
                </div>
            </div>
        </div>
    </div>

    <!-- 用户列表 -->
    <table class="table table-striped">
        <thead>
            <tr>
                <th>邮箱</th>
                <th>用户名</th>
                <th>邮箱已确认</th>
                <th>操作</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var user in Users)
            {
                <tr>
                    <td>@user.Email</td>
                    <td>@user.UserName</td>
                    <td>@(user.EmailConfirmed ? "是" : "否")</td>
                    <td>
                        <button class="btn btn-sm btn-info" @onclick="() => OpenRoleAssignmentModal(user)">分配角色</button>
                        <button class="btn btn-sm btn-warning ms-2" @onclick="() => EditUser(user)">编辑</button>
                        <button class="btn btn-sm btn-danger ms-2" @onclick="() => DeleteUser(user)">删除</button>
                    </td>
                </tr>
            }
        </tbody>
    </table>

    <!-- 角色分配模态框 -->
    @if (SelectedUser != null)
    {
        <div class="modal show d-block" style="background-color: rgba(0,0,0,0.5)">
            <div class="modal-dialog">
                <div class="modal-content">
                    <div class="modal-header">
                        <h5 class="modal-title">为 @SelectedUser.Email 分配角色</h5>
                        <button type="button" class="btn-close" @onclick="() => SelectedUser = null"></button>
                    </div>
                    <div class="modal-body">
                        @foreach (var role in AllRoles)
                        {
                            <div class="form-check">
                                <input class="form-check-input" type="checkbox" 
                                       id="@role.Id" 
                                       @bind="SelectedRoles" 
                                       value="@role.Name" />
                                <label class="form-check-label" for="@role.Id">
                                    @role.Name
                                </label>
                            </div>
                        }
                    </div>
                    <div class="modal-footer">
                        <button class="btn btn-secondary" @onclick="() => SelectedUser = null">取消</button>
                        <button class="btn btn-primary" @onclick="SaveUserRoles">保存</button>
                    </div>
                </div>
            </div>
        </div>
    }
</div>

@code {
    private List<IdentityUser> Users = new();
    private List<IdentityRole> AllRoles = new();
    private string NewUserEmail = string.Empty;
    private string NewUserPassword = string.Empty;
    private IdentityUser? SelectedUser;
    private List<string> SelectedRoles = new();

    protected override async Task OnInitializedAsync()
    {
        await LoadUsers();
        AllRoles = (await RoleManager.Roles.ToListAsync()).OrderBy(r => r.Name).ToList();
    }

    private async Task LoadUsers()
    {
        Users = (await UserManager.Users.ToListAsync()).OrderBy(u => u.Email).ToList();
        StateHasChanged();
    }

    private async Task CreateUser()
    {
        if (string.IsNullOrWhiteSpace(NewUserEmail) || string.IsNullOrWhiteSpace(NewUserPassword)) return;

        var user = new IdentityUser { UserName = NewUserEmail, Email = NewUserEmail };
        var result = await UserManager.CreateAsync(user, NewUserPassword);
        if (result.Succeeded)
        {
            NewUserEmail = string.Empty;
            NewUserPassword = string.Empty;
            await LoadUsers();
        }
        else
        {
            foreach (var error in result.Errors)
            {
                Logger.LogError("创建用户失败:{Error}", error.Description);
            }
        }
    }

    private async Task OpenRoleAssignmentModal(IdentityUser user)
    {
        SelectedUser = user;
        var currentRoles = await UserManager.GetRolesAsync(user);
        SelectedRoles = currentRoles.ToList();
    }

    private async Task SaveUserRoles()
    {
        if (SelectedUser == null) return;

        var currentRoles = await UserManager.GetRolesAsync(SelectedUser);
        var rolesToAdd = SelectedRoles.Except(currentRoles).ToList();
        var rolesToRemove = currentRoles.Except(SelectedRoles).ToList();

        await UserManager.AddToRolesAsync(SelectedUser, rolesToAdd);
        await UserManager.RemoveFromRolesAsync(SelectedUser, rolesToRemove);

        SelectedUser = null;
        SelectedRoles.Clear();
    }

    private async Task EditUser(IdentityUser user)
    {
        // 示例:更新邮箱,可扩展为编辑用户名、重置密码等逻辑
        var newEmail = await Prompt("输入新邮箱", user.Email);
        if (string.IsNullOrWhiteSpace(newEmail)) return;

        user.Email = newEmail.Trim();
        user.UserName = newEmail.Trim();
        var result = await UserManager.UpdateAsync(user);
        if (result.Succeeded)
        {
            await LoadUsers();
        }
        else
        {
            foreach (var error in result.Errors)
            {
                Logger.LogError("更新用户失败:{Error}", error.Description);
            }
        }
    }

    private async Task DeleteUser(IdentityUser user)
    {
        var confirm = await Confirm($"确定要删除用户 {user.Email} 吗?");
        if (!confirm) return;

        var result = await UserManager.DeleteAsync(user);
        if (result.Succeeded)
        {
            await LoadUsers();
        }
        else
        {
            foreach (var error in result.Errors)
            {
                Logger.LogError("删除用户失败:{Error}", error.Description);
            }
        }
    }

    // 模拟弹窗方法,实际项目可使用Blazored.Modal等组件
    private async Task<string> Prompt(string title, string defaultValue)
    {
        return defaultValue;
    }

    private async Task<bool> Confirm(string message)
    {
        return true;
    }
}

四、权限控制

在Shared/NavMenu.razor中添加管理页面的导航链接,仅管理员可见:

@inject AuthenticationStateProvider AuthenticationStateProvider

...

@if (IsAdmin)
{
    <div class="nav-item px-3">
        <NavLink class="nav-link" href="role-management">
            <span class="oi oi-list-rich" aria-hidden="true"></span> 角色管理
        </NavLink>
    </div>
    <div class="nav-item px-3">
        <NavLink class="nav-link" href="user-management">
            <span class="oi oi-people" aria-hidden="true"></span> 用户管理
        </NavLink>
    </div>
}

@code {
    private bool IsAdmin { get; set; }

    protected override async Task OnInitializedAsync()
    {
        var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
        var user = authState.User;
        IsAdmin = user.IsInRole("Admin");
    }
}

五、初始化管理员账号

在Program.cs中添加初始化逻辑,创建默认管理员:

// 在app.Run()之前添加
using (var scope = app.Services.CreateScope())
{
    var services = scope.ServiceProvider;
    var roleManager = services.GetRequiredService<RoleManager<IdentityRole>>();
    var userManager = services.GetRequiredService<UserManager<IdentityUser>>();

    // 创建Admin角色
    if (!await roleManager.RoleExistsAsync("Admin"))
    {
        await roleManager.CreateAsync(new IdentityRole("Admin"));
    }

    // 创建管理员用户
    var adminEmail = "admin@example.com";
    var adminUser = await userManager.FindByEmailAsync(adminEmail);
    if (adminUser == null)
    {
        adminUser = new IdentityUser { UserName = adminEmail, Email = adminEmail, EmailConfirmed = true };
        await userManager.CreateAsync(adminUser, "Admin@123");
        await userManager.AddToRoleAsync(adminUser, "Admin");
    }
}

app.Run();

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 23:55:26