mirror of
https://github.com/AIDotNet/AntSK.git
synced 2026-02-17 22:10:14 +08:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5e032e3733 | ||
|
|
abed362ff2 | ||
|
|
1a3881e7a4 | ||
|
|
ea8dd21478 | ||
|
|
5ec918a2f9 | ||
|
|
08d3a0aa3d | ||
|
|
4044355ae7 |
140
docs/RBAC_README.md
Normal file
140
docs/RBAC_README.md
Normal file
@@ -0,0 +1,140 @@
|
||||
# 角色基础授权系统 (Role-Based Access Control)
|
||||
|
||||
## 概述
|
||||
|
||||
本系统实现了完整的角色基础授权功能,支持将权限绑定到角色,角色再绑定给用户,提供灵活的权限管理能力。
|
||||
|
||||
## 数据库结构
|
||||
|
||||
### 核心表
|
||||
|
||||
1. **Roles (角色表)**
|
||||
- Id: 角色ID (主键)
|
||||
- Name: 角色名称
|
||||
- Code: 角色编码 (用于授权验证)
|
||||
- Description: 角色描述
|
||||
- IsEnabled: 是否启用
|
||||
- CreateTime: 创建时间
|
||||
|
||||
2. **Permissions (权限表)**
|
||||
- Id: 权限ID (主键)
|
||||
- Name: 权限名称
|
||||
- Code: 权限编码 (用于授权验证)
|
||||
- Type: 权限类型 (Menu-菜单权限, Operation-操作权限)
|
||||
- Description: 权限描述
|
||||
- CreateTime: 创建时间
|
||||
|
||||
3. **RolePermissions (角色权限关联表)**
|
||||
- Id: 关联ID (主键)
|
||||
- RoleId: 角色ID
|
||||
- PermissionId: 权限ID
|
||||
- CreateTime: 创建时间
|
||||
|
||||
4. **UserRoles (用户角色关联表)**
|
||||
- Id: 关联ID (主键)
|
||||
- UserId: 用户ID
|
||||
- RoleId: 角色ID
|
||||
- CreateTime: 创建时间
|
||||
|
||||
## 默认角色和权限
|
||||
|
||||
系统首次运行时会自动初始化以下角色和权限:
|
||||
|
||||
### 默认角色
|
||||
|
||||
1. **AntSKAdmin (管理员)**
|
||||
- 拥有系统所有权限
|
||||
- 可以管理用户、角色、权限等
|
||||
|
||||
2. **AntSKUser (普通用户)**
|
||||
- 拥有基本功能权限
|
||||
- 包括:聊天、应用、知识库
|
||||
|
||||
### 默认权限
|
||||
|
||||
系统包含以下菜单权限:
|
||||
- chat: 聊天
|
||||
- app: 应用
|
||||
- kms: 知识库
|
||||
- plugins.apilist: API管理
|
||||
- plugins.funlist: 函数管理
|
||||
- modelmanager.modellist: 模型管理
|
||||
- setting.user: 用户管理
|
||||
- setting.role: 角色管理
|
||||
- setting.chathistory: 聊天记录
|
||||
- setting.delkms: 删除向量表
|
||||
|
||||
## 使用说明
|
||||
|
||||
### 1. 角色管理
|
||||
|
||||
访问 `/setting/rolelist` 可以进行角色管理:
|
||||
- 查看所有角色
|
||||
- 创建新角色
|
||||
- 编辑角色信息
|
||||
- 为角色分配权限
|
||||
- 删除角色
|
||||
|
||||
### 2. 用户管理
|
||||
|
||||
访问 `/setting/userlist` 可以进行用户管理:
|
||||
- 创建用户时可以分配角色
|
||||
- 编辑用户时可以修改角色分配
|
||||
- 用户可以拥有多个角色
|
||||
|
||||
### 3. 授权验证
|
||||
|
||||
系统支持两种授权方式:
|
||||
|
||||
**方式一:基于角色的授权**
|
||||
```csharp
|
||||
@attribute [Authorize(Roles = "AntSKAdmin")]
|
||||
```
|
||||
|
||||
**方式二:基于多角色的授权**
|
||||
```csharp
|
||||
@attribute [Authorize(Roles = "AntSKAdmin,AntSKUser")]
|
||||
```
|
||||
|
||||
## 技术实现
|
||||
|
||||
### 认证流程
|
||||
|
||||
1. 用户登录时,系统从数据库加载用户的角色和权限
|
||||
2. 将所有角色添加到用户的Claims中
|
||||
3. 将权限列表存储到UserSession中供后续使用
|
||||
4. 支持多个角色同时验证
|
||||
|
||||
### 向后兼容
|
||||
|
||||
- 保留了原有的MenuRole字段,支持逐步迁移
|
||||
- 硬编码的管理员账号继续使用AntSKAdmin角色
|
||||
- 新用户如果没有分配角色,默认使用AntSKUser角色
|
||||
|
||||
## 安全性
|
||||
|
||||
1. **角色验证**: 只有AntSKAdmin角色可以访问角色和用户管理页面
|
||||
2. **级联删除**: 删除角色时会自动删除相关的角色权限和用户角色关联
|
||||
3. **启用状态**: 角色支持启用/禁用状态,禁用的角色不会加载权限
|
||||
4. **多层级保护**: 数据库层、业务层、UI层都有权限验证
|
||||
|
||||
## 扩展建议
|
||||
|
||||
1. **操作权限**: 可以在Permissions表中添加Type为"Operation"的权限,用于控制具体操作
|
||||
2. **权限缓存**: 可以考虑添加权限缓存机制,提高性能
|
||||
3. **审计日志**: 可以添加角色和权限变更的审计日志
|
||||
4. **批量操作**: 可以添加批量分配角色、批量分配权限的功能
|
||||
|
||||
## 常见问题
|
||||
|
||||
**Q: 如何添加新的权限?**
|
||||
A: 可以通过代码在InitRolesAndPermissions方法中添加,或者后续可以开发权限管理UI。
|
||||
|
||||
**Q: 用户可以有多个角色吗?**
|
||||
A: 可以。系统支持一个用户拥有多个角色,最终拥有所有角色的权限并集。
|
||||
|
||||
**Q: 如何处理权限冲突?**
|
||||
A: 系统采用"允许优先"策略,只要用户的任一角色拥有某项权限,用户就拥有该权限。
|
||||
|
||||
**Q: 删除角色会影响已登录的用户吗?**
|
||||
A: 会的。用户下次登录时会重新加载角色和权限,已删除的角色将不再生效。
|
||||
@@ -836,6 +836,126 @@
|
||||
部署名,azure需要使用
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:AntSK.Domain.Repositories.Permissions">
|
||||
<summary>
|
||||
权限表
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:AntSK.Domain.Repositories.Permissions.Id">
|
||||
<summary>
|
||||
权限ID
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:AntSK.Domain.Repositories.Permissions.Name">
|
||||
<summary>
|
||||
权限名称
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:AntSK.Domain.Repositories.Permissions.Code">
|
||||
<summary>
|
||||
权限编码
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:AntSK.Domain.Repositories.Permissions.Type">
|
||||
<summary>
|
||||
权限类型(Menu-菜单权限, Operation-操作权限)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:AntSK.Domain.Repositories.Permissions.Description">
|
||||
<summary>
|
||||
权限描述
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:AntSK.Domain.Repositories.Permissions.CreateTime">
|
||||
<summary>
|
||||
创建时间
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:AntSK.Domain.Repositories.RolePermissions">
|
||||
<summary>
|
||||
角色权限关联表
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:AntSK.Domain.Repositories.RolePermissions.Id">
|
||||
<summary>
|
||||
关联ID
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:AntSK.Domain.Repositories.RolePermissions.RoleId">
|
||||
<summary>
|
||||
角色ID
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:AntSK.Domain.Repositories.RolePermissions.PermissionId">
|
||||
<summary>
|
||||
权限ID
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:AntSK.Domain.Repositories.RolePermissions.CreateTime">
|
||||
<summary>
|
||||
创建时间
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:AntSK.Domain.Repositories.Roles">
|
||||
<summary>
|
||||
角色表
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:AntSK.Domain.Repositories.Roles.Id">
|
||||
<summary>
|
||||
角色ID
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:AntSK.Domain.Repositories.Roles.Name">
|
||||
<summary>
|
||||
角色名称
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:AntSK.Domain.Repositories.Roles.Code">
|
||||
<summary>
|
||||
角色编码
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:AntSK.Domain.Repositories.Roles.Description">
|
||||
<summary>
|
||||
角色描述
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:AntSK.Domain.Repositories.Roles.IsEnabled">
|
||||
<summary>
|
||||
是否启用
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:AntSK.Domain.Repositories.Roles.CreateTime">
|
||||
<summary>
|
||||
创建时间
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:AntSK.Domain.Repositories.UserRoles">
|
||||
<summary>
|
||||
用户角色关联表
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:AntSK.Domain.Repositories.UserRoles.Id">
|
||||
<summary>
|
||||
关联ID
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:AntSK.Domain.Repositories.UserRoles.UserId">
|
||||
<summary>
|
||||
用户ID
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:AntSK.Domain.Repositories.UserRoles.RoleId">
|
||||
<summary>
|
||||
角色ID
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:AntSK.Domain.Repositories.UserRoles.CreateTime">
|
||||
<summary>
|
||||
创建时间
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:AntSK.Domain.Repositories.Users.No">
|
||||
<summary>
|
||||
工号,用于登陆
|
||||
|
||||
@@ -81,10 +81,98 @@ namespace AntSK.Domain.Common.DependencyInjection
|
||||
llamafactoryStart.Value = "false";
|
||||
_dic_Repository.Insert(llamafactoryStart);
|
||||
}
|
||||
|
||||
// 初始化角色和权限
|
||||
InitRolesAndPermissions(scope.ServiceProvider);
|
||||
|
||||
_logger.LogInformation("初始化数据库初始数据完成");
|
||||
}
|
||||
return app;
|
||||
}
|
||||
|
||||
private static void InitRolesAndPermissions(IServiceProvider serviceProvider)
|
||||
{
|
||||
var _roles_Repository = serviceProvider.GetRequiredService<IRoles_Repositories>();
|
||||
var _permissions_Repository = serviceProvider.GetRequiredService<IPermissions_Repositories>();
|
||||
var _rolePermissions_Repository = serviceProvider.GetRequiredService<IRolePermissions_Repositories>();
|
||||
|
||||
// 检查是否已经初始化
|
||||
if (_roles_Repository.IsAny(r => r.Code == "AntSKAdmin"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 创建管理员角色
|
||||
var adminRole = new Roles
|
||||
{
|
||||
Id = Guid.NewGuid().ToString(),
|
||||
Name = "管理员",
|
||||
Code = "AntSKAdmin",
|
||||
Description = "系统管理员,拥有所有权限",
|
||||
IsEnabled = true,
|
||||
CreateTime = DateTime.Now
|
||||
};
|
||||
_roles_Repository.Insert(adminRole);
|
||||
|
||||
// 创建普通用户角色
|
||||
var userRole = new Roles
|
||||
{
|
||||
Id = Guid.NewGuid().ToString(),
|
||||
Name = "普通用户",
|
||||
Code = "AntSKUser",
|
||||
Description = "普通用户,拥有基本功能权限",
|
||||
IsEnabled = true,
|
||||
CreateTime = DateTime.Now
|
||||
};
|
||||
_roles_Repository.Insert(userRole);
|
||||
|
||||
// 创建菜单权限
|
||||
var menuPermissions = new List<Permissions>
|
||||
{
|
||||
new Permissions { Id = Guid.NewGuid().ToString(), Name = "聊天", Code = "chat", Type = "Menu", Description = "聊天功能权限" },
|
||||
new Permissions { Id = Guid.NewGuid().ToString(), Name = "应用", Code = "app", Type = "Menu", Description = "应用管理权限" },
|
||||
new Permissions { Id = Guid.NewGuid().ToString(), Name = "知识库", Code = "kms", Type = "Menu", Description = "知识库管理权限" },
|
||||
new Permissions { Id = Guid.NewGuid().ToString(), Name = "API管理", Code = "plugins.apilist", Type = "Menu", Description = "API管理权限" },
|
||||
new Permissions { Id = Guid.NewGuid().ToString(), Name = "函数管理", Code = "plugins.funlist", Type = "Menu", Description = "函数管理权限" },
|
||||
new Permissions { Id = Guid.NewGuid().ToString(), Name = "模型管理", Code = "modelmanager.modellist", Type = "Menu", Description = "模型管理权限" },
|
||||
new Permissions { Id = Guid.NewGuid().ToString(), Name = "用户管理", Code = "setting.user", Type = "Menu", Description = "用户管理权限" },
|
||||
new Permissions { Id = Guid.NewGuid().ToString(), Name = "角色管理", Code = "setting.role", Type = "Menu", Description = "角色管理权限" },
|
||||
new Permissions { Id = Guid.NewGuid().ToString(), Name = "聊天记录", Code = "setting.chathistory", Type = "Menu", Description = "聊天记录权限" },
|
||||
new Permissions { Id = Guid.NewGuid().ToString(), Name = "删除向量表", Code = "setting.delkms", Type = "Menu", Description = "删除向量表权限" }
|
||||
};
|
||||
|
||||
foreach (var permission in menuPermissions)
|
||||
{
|
||||
_permissions_Repository.Insert(permission);
|
||||
}
|
||||
|
||||
// 为管理员角色分配所有权限
|
||||
foreach (var permission in menuPermissions)
|
||||
{
|
||||
_rolePermissions_Repository.Insert(new RolePermissions
|
||||
{
|
||||
Id = Guid.NewGuid().ToString(),
|
||||
RoleId = adminRole.Id,
|
||||
PermissionId = permission.Id,
|
||||
CreateTime = DateTime.Now
|
||||
});
|
||||
}
|
||||
|
||||
// 为普通用户角色分配基本权限(聊天、应用、知识库)
|
||||
var basicPermissions = menuPermissions.Where(p => p.Code == "chat" || p.Code == "app" || p.Code == "kms").ToList();
|
||||
foreach (var permission in basicPermissions)
|
||||
{
|
||||
_rolePermissions_Repository.Insert(new RolePermissions
|
||||
{
|
||||
Id = Guid.NewGuid().ToString(),
|
||||
RoleId = userRole.Id,
|
||||
PermissionId = permission.Id,
|
||||
CreateTime = DateTime.Now
|
||||
});
|
||||
}
|
||||
|
||||
_logger.LogInformation("初始化角色和权限完成");
|
||||
}
|
||||
/// <summary>
|
||||
/// 加载数据库的插件
|
||||
/// </summary>
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
using AntSK.Domain.Repositories.Base;
|
||||
|
||||
namespace AntSK.Domain.Repositories
|
||||
{
|
||||
public interface IPermissions_Repositories : IRepository<Permissions>
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
using SqlSugar;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace AntSK.Domain.Repositories
|
||||
{
|
||||
/// <summary>
|
||||
/// 权限表
|
||||
/// </summary>
|
||||
[SugarTable("Permissions")]
|
||||
public partial class Permissions
|
||||
{
|
||||
/// <summary>
|
||||
/// 权限ID
|
||||
/// </summary>
|
||||
[SugarColumn(IsPrimaryKey = true)]
|
||||
public string Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 权限名称
|
||||
/// </summary>
|
||||
[Required]
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 权限编码
|
||||
/// </summary>
|
||||
[Required]
|
||||
public string Code { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 权限类型(Menu-菜单权限, Operation-操作权限)
|
||||
/// </summary>
|
||||
[Required]
|
||||
public string Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 权限描述
|
||||
/// </summary>
|
||||
public string? Description { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 创建时间
|
||||
/// </summary>
|
||||
public DateTime CreateTime { get; set; } = DateTime.Now;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
using AntSK.Domain.Common.DependencyInjection;
|
||||
using AntSK.Domain.Repositories.Base;
|
||||
|
||||
namespace AntSK.Domain.Repositories
|
||||
{
|
||||
[ServiceDescription(typeof(IPermissions_Repositories), ServiceLifetime.Scoped)]
|
||||
public class Permissions_Repositories : Repository<Permissions>, IPermissions_Repositories
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using AntSK.Domain.Repositories.Base;
|
||||
|
||||
namespace AntSK.Domain.Repositories
|
||||
{
|
||||
public interface IRoles_Repositories : IRepository<Roles>
|
||||
{
|
||||
}
|
||||
}
|
||||
45
src/AntSK.Domain/Repositories/Setting/Role/Roles.cs
Normal file
45
src/AntSK.Domain/Repositories/Setting/Role/Roles.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
using SqlSugar;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace AntSK.Domain.Repositories
|
||||
{
|
||||
/// <summary>
|
||||
/// 角色表
|
||||
/// </summary>
|
||||
[SugarTable("Roles")]
|
||||
public partial class Roles
|
||||
{
|
||||
/// <summary>
|
||||
/// 角色ID
|
||||
/// </summary>
|
||||
[SugarColumn(IsPrimaryKey = true)]
|
||||
public string Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 角色名称
|
||||
/// </summary>
|
||||
[Required]
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 角色编码
|
||||
/// </summary>
|
||||
[Required]
|
||||
public string Code { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 角色描述
|
||||
/// </summary>
|
||||
public string? Description { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否启用
|
||||
/// </summary>
|
||||
public bool IsEnabled { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// 创建时间
|
||||
/// </summary>
|
||||
public DateTime CreateTime { get; set; } = DateTime.Now;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
using AntSK.Domain.Common.DependencyInjection;
|
||||
using AntSK.Domain.Repositories.Base;
|
||||
|
||||
namespace AntSK.Domain.Repositories
|
||||
{
|
||||
[ServiceDescription(typeof(IRoles_Repositories), ServiceLifetime.Scoped)]
|
||||
public class Roles_Repositories : Repository<Roles>, IRoles_Repositories
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using AntSK.Domain.Repositories.Base;
|
||||
|
||||
namespace AntSK.Domain.Repositories
|
||||
{
|
||||
public interface IRolePermissions_Repositories : IRepository<RolePermissions>
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using SqlSugar;
|
||||
|
||||
namespace AntSK.Domain.Repositories
|
||||
{
|
||||
/// <summary>
|
||||
/// 角色权限关联表
|
||||
/// </summary>
|
||||
[SugarTable("RolePermissions")]
|
||||
public partial class RolePermissions
|
||||
{
|
||||
/// <summary>
|
||||
/// 关联ID
|
||||
/// </summary>
|
||||
[SugarColumn(IsPrimaryKey = true)]
|
||||
public string Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 角色ID
|
||||
/// </summary>
|
||||
public string RoleId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 权限ID
|
||||
/// </summary>
|
||||
public string PermissionId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 创建时间
|
||||
/// </summary>
|
||||
public DateTime CreateTime { get; set; } = DateTime.Now;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
using AntSK.Domain.Common.DependencyInjection;
|
||||
using AntSK.Domain.Repositories.Base;
|
||||
|
||||
namespace AntSK.Domain.Repositories
|
||||
{
|
||||
[ServiceDescription(typeof(IRolePermissions_Repositories), ServiceLifetime.Scoped)]
|
||||
public class RolePermissions_Repositories : Repository<RolePermissions>, IRolePermissions_Repositories
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using AntSK.Domain.Repositories.Base;
|
||||
|
||||
namespace AntSK.Domain.Repositories
|
||||
{
|
||||
public interface IUserRoles_Repositories : IRepository<UserRoles>
|
||||
{
|
||||
}
|
||||
}
|
||||
32
src/AntSK.Domain/Repositories/Setting/UserRole/UserRoles.cs
Normal file
32
src/AntSK.Domain/Repositories/Setting/UserRole/UserRoles.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using SqlSugar;
|
||||
|
||||
namespace AntSK.Domain.Repositories
|
||||
{
|
||||
/// <summary>
|
||||
/// 用户角色关联表
|
||||
/// </summary>
|
||||
[SugarTable("UserRoles")]
|
||||
public partial class UserRoles
|
||||
{
|
||||
/// <summary>
|
||||
/// 关联ID
|
||||
/// </summary>
|
||||
[SugarColumn(IsPrimaryKey = true)]
|
||||
public string Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 用户ID
|
||||
/// </summary>
|
||||
public string UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 角色ID
|
||||
/// </summary>
|
||||
public string RoleId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 创建时间
|
||||
/// </summary>
|
||||
public DateTime CreateTime { get; set; } = DateTime.Now;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
using AntSK.Domain.Common.DependencyInjection;
|
||||
using AntSK.Domain.Repositories.Base;
|
||||
|
||||
namespace AntSK.Domain.Repositories
|
||||
{
|
||||
[ServiceDescription(typeof(IUserRoles_Repositories), ServiceLifetime.Scoped)]
|
||||
public class UserRoles_Repositories : Repository<UserRoles>, IUserRoles_Repositories
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -4,5 +4,7 @@
|
||||
{
|
||||
public string UserName { get; set; }
|
||||
public string Role { get; set; }
|
||||
public List<string>? Roles { get; set; }
|
||||
public List<string>? Permissions { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
61
src/AntSK/Pages/Setting/Role/AddRole.razor
Normal file
61
src/AntSK/Pages/Setting/Role/AddRole.razor
Normal file
@@ -0,0 +1,61 @@
|
||||
@namespace AntSK.Pages.Setting.Role
|
||||
@using AntSK.Domain.Repositories
|
||||
@using AntSK.Models
|
||||
@page "/setting/role/add"
|
||||
@page "/setting/role/add/{RoleId}"
|
||||
@using AntSK.Services.Auth
|
||||
@inherits AuthComponentBase
|
||||
@using Microsoft.AspNetCore.Authorization
|
||||
@attribute [Authorize(Roles = "AntSKAdmin")]
|
||||
|
||||
<PageContainer Title="新增角色">
|
||||
<ChildContent>
|
||||
<Card>
|
||||
<Form Model="@_roleModel"
|
||||
Style="margin-top: 8px;"
|
||||
OnFinish="HandleSubmit">
|
||||
<FormItem Label="角色名称" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
|
||||
<Input Placeholder="请输入角色名称" @bind-Value="@context.Name" />
|
||||
</FormItem>
|
||||
<FormItem Label="角色编码" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
|
||||
<Input Placeholder="请输入角色编码" @bind-Value="@context.Code" />
|
||||
</FormItem>
|
||||
<FormItem Label="角色描述" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
|
||||
<Input Placeholder="请输入角色描述" @bind-Value="@context.Description" />
|
||||
</FormItem>
|
||||
<FormItem Label="是否启用" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
|
||||
<Switch @bind-Checked="@context.IsEnabled" />
|
||||
</FormItem>
|
||||
|
||||
<FormItem Label="权限分配" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
|
||||
<Select Mode="multiple"
|
||||
@bind-Values="_permissionIds"
|
||||
Placeholder="选择权限"
|
||||
TItemValue="string"
|
||||
TItem="string"
|
||||
Size="@AntSizeLDSType.Default">
|
||||
<SelectOptions>
|
||||
@foreach (var permission in _allPermissions)
|
||||
{
|
||||
<SelectOption TItem="string" TItemValue="string" Value="@permission.Id" Label="@permission.Name" />
|
||||
}
|
||||
</SelectOptions>
|
||||
</Select>
|
||||
</FormItem>
|
||||
|
||||
<FormItem Label=" " Style="margin-top:32px" WrapperCol="LayoutModel._submitFormLayout.WrapperCol">
|
||||
<Button Type="primary" OnClick="HandleSubmit">
|
||||
保存
|
||||
</Button>
|
||||
<Button OnClick="Back">
|
||||
返回
|
||||
</Button>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</Card>
|
||||
</ChildContent>
|
||||
</PageContainer>
|
||||
|
||||
@code {
|
||||
|
||||
}
|
||||
103
src/AntSK/Pages/Setting/Role/AddRole.razor.cs
Normal file
103
src/AntSK/Pages/Setting/Role/AddRole.razor.cs
Normal file
@@ -0,0 +1,103 @@
|
||||
using AntDesign;
|
||||
using AntSK.Domain.Repositories;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace AntSK.Pages.Setting.Role
|
||||
{
|
||||
public partial class AddRole
|
||||
{
|
||||
[Parameter]
|
||||
public string RoleId { get; set; }
|
||||
[Inject] protected IRoles_Repositories _roles_Repositories { get; set; }
|
||||
[Inject] protected IPermissions_Repositories _permissions_Repositories { get; set; }
|
||||
[Inject] protected IRolePermissions_Repositories _rolePermissions_Repositories { get; set; }
|
||||
[Inject] protected MessageService? Message { get; set; }
|
||||
|
||||
private Roles _roleModel = new Roles();
|
||||
private List<Permissions> _allPermissions = new List<Permissions>();
|
||||
private IEnumerable<string> _permissionIds;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await base.OnInitializedAsync();
|
||||
|
||||
// 加载所有权限
|
||||
_allPermissions = _permissions_Repositories.GetList();
|
||||
|
||||
if (!string.IsNullOrEmpty(RoleId))
|
||||
{
|
||||
_roleModel = _roles_Repositories.GetFirst(p => p.Id == RoleId);
|
||||
|
||||
// 加载角色已有的权限
|
||||
var rolePermissions = _rolePermissions_Repositories.GetList(p => p.RoleId == RoleId);
|
||||
_permissionIds = rolePermissions.Select(rp => rp.PermissionId);
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleSubmit()
|
||||
{
|
||||
if (string.IsNullOrEmpty(RoleId))
|
||||
{
|
||||
//新增
|
||||
_roleModel.Id = Guid.NewGuid().ToString();
|
||||
_roleModel.CreateTime = DateTime.Now;
|
||||
|
||||
if (_roles_Repositories.IsAny(p => p.Code == _roleModel.Code))
|
||||
{
|
||||
_ = Message.Error("角色编码已存在!", 2);
|
||||
return;
|
||||
}
|
||||
_roles_Repositories.Insert(_roleModel);
|
||||
|
||||
// 添加角色权限关联
|
||||
if (_permissionIds != null)
|
||||
{
|
||||
foreach (var permissionId in _permissionIds)
|
||||
{
|
||||
_rolePermissions_Repositories.Insert(new RolePermissions
|
||||
{
|
||||
Id = Guid.NewGuid().ToString(),
|
||||
RoleId = _roleModel.Id,
|
||||
PermissionId = permissionId,
|
||||
CreateTime = DateTime.Now
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//修改
|
||||
_roles_Repositories.Update(_roleModel);
|
||||
|
||||
// 先删除旧的角色权限关联
|
||||
var oldRolePermissions = _rolePermissions_Repositories.GetList(p => p.RoleId == RoleId);
|
||||
foreach (var rp in oldRolePermissions)
|
||||
{
|
||||
_rolePermissions_Repositories.Delete(rp.Id);
|
||||
}
|
||||
|
||||
// 添加新的角色权限关联
|
||||
if (_permissionIds != null)
|
||||
{
|
||||
foreach (var permissionId in _permissionIds)
|
||||
{
|
||||
_rolePermissions_Repositories.Insert(new RolePermissions
|
||||
{
|
||||
Id = Guid.NewGuid().ToString(),
|
||||
RoleId = _roleModel.Id,
|
||||
PermissionId = permissionId,
|
||||
CreateTime = DateTime.Now
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Back();
|
||||
}
|
||||
|
||||
private void Back()
|
||||
{
|
||||
NavigationManager.NavigateTo("/setting/rolelist");
|
||||
}
|
||||
}
|
||||
}
|
||||
72
src/AntSK/Pages/Setting/Role/RoleList.razor
Normal file
72
src/AntSK/Pages/Setting/Role/RoleList.razor
Normal file
@@ -0,0 +1,72 @@
|
||||
@namespace AntSK.Pages.Setting.Role
|
||||
@using AntSK.Domain.Repositories
|
||||
@page "/setting/rolelist"
|
||||
@inject NavigationManager NavigationManager
|
||||
@using AntSK.Services.Auth
|
||||
@inherits AuthComponentBase
|
||||
@using Microsoft.AspNetCore.Authorization
|
||||
@attribute [Authorize(Roles = "AntSKAdmin")]
|
||||
|
||||
<div>
|
||||
<PageContainer Title="角色管理">
|
||||
<ChildContent>
|
||||
<div class="standardList">
|
||||
|
||||
<Card Class="listCard"
|
||||
Title="角色列表"
|
||||
Style="margin-top: 24px;"
|
||||
BodyStyle="padding: 0 32px 40px 32px">
|
||||
<Extra>
|
||||
<div class="extraContent">
|
||||
|
||||
<Search Class="extraContentSearch" Placeholder="查询" @bind-Value="_searchKeyword" OnSearch="OnSearch" />
|
||||
</div>
|
||||
</Extra>
|
||||
<ChildContent>
|
||||
<Button Type="dashed"
|
||||
Style="width: 100%; margin-bottom: 8px;"
|
||||
OnClick="AddRole">
|
||||
<Icon Type="plus" Theme="outline" />
|
||||
新增角色
|
||||
</Button>
|
||||
|
||||
<AntList TItem="Roles"
|
||||
DataSource="_data"
|
||||
ItemLayout="ListItemLayout.Horizontal">
|
||||
<ListItem Actions="new[] {
|
||||
edit(()=> Edit(context.Id)),
|
||||
delete(async ()=>await Delete(context.Id))
|
||||
}" Style="width:100%">
|
||||
<div class="listContent" style="width:100%">
|
||||
<div class="listContentItem" style="width:20%">
|
||||
<b>角色名称</b>
|
||||
<p>@context.Name</p>
|
||||
</div>
|
||||
<div class="listContentItem" style="width:20%">
|
||||
<b>角色编码</b>
|
||||
<p>@context.Code</p>
|
||||
</div>
|
||||
<div class="listContentItem" style="width:30%">
|
||||
<b>描述</b>
|
||||
<p>@context.Description</p>
|
||||
</div>
|
||||
<div class="listContentItem" style="width:15%">
|
||||
<b>状态</b>
|
||||
<p>@(context.IsEnabled ? "启用" : "禁用")</p>
|
||||
</div>
|
||||
</div>
|
||||
</ListItem>
|
||||
</AntList>
|
||||
</ChildContent>
|
||||
</Card>
|
||||
</div>
|
||||
</ChildContent>
|
||||
</PageContainer>
|
||||
</div>
|
||||
|
||||
@code
|
||||
{
|
||||
RenderFragment edit(Action clickAction) =>@<a key="edit" @onclick="@clickAction">修改</a>;
|
||||
RenderFragment delete(Action clickAction) =>@<a key="delete" @onclick="@clickAction">删除</a>;
|
||||
|
||||
}
|
||||
84
src/AntSK/Pages/Setting/Role/RoleList.razor.cs
Normal file
84
src/AntSK/Pages/Setting/Role/RoleList.razor.cs
Normal file
@@ -0,0 +1,84 @@
|
||||
using AntDesign;
|
||||
using AntSK.Domain.Repositories;
|
||||
using AntSK.Models;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace AntSK.Pages.Setting.Role
|
||||
{
|
||||
public partial class RoleList
|
||||
{
|
||||
private readonly BasicListFormModel _model = new BasicListFormModel();
|
||||
|
||||
private List<Roles> _data;
|
||||
|
||||
private string _searchKeyword;
|
||||
|
||||
[Inject]
|
||||
protected IRoles_Repositories _roles_Repositories { get; set; }
|
||||
[Inject]
|
||||
protected IRolePermissions_Repositories _rolePermissions_Repositories { get; set; }
|
||||
[Inject]
|
||||
protected IUserRoles_Repositories _userRoles_Repositories { get; set; }
|
||||
[Inject]
|
||||
IConfirmService _confirmService { get; set; }
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await base.OnInitializedAsync();
|
||||
await InitData();
|
||||
}
|
||||
private async Task InitData(string searchKey = null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(searchKey))
|
||||
{
|
||||
_data = _roles_Repositories.GetList();
|
||||
}
|
||||
else
|
||||
{
|
||||
_data = _roles_Repositories.GetList(p => p.Name.Contains(searchKey) || p.Code.Contains(searchKey) || (p.Description != null && p.Description.Contains(searchKey)));
|
||||
}
|
||||
await InvokeAsync(StateHasChanged);
|
||||
}
|
||||
public async Task OnSearch()
|
||||
{
|
||||
await InitData(_searchKeyword);
|
||||
}
|
||||
|
||||
public async Task AddRole()
|
||||
{
|
||||
NavigationManager.NavigateTo("/setting/role/add");
|
||||
}
|
||||
|
||||
public void Edit(string roleid)
|
||||
{
|
||||
NavigationManager.NavigateTo("/setting/role/add/" + roleid);
|
||||
}
|
||||
|
||||
public async Task Delete(string roleid)
|
||||
{
|
||||
var content = "是否确认删除此角色";
|
||||
var title = "删除";
|
||||
var result = await _confirmService.Show(content, title, ConfirmButtons.YesNo);
|
||||
if (result == ConfirmResult.Yes)
|
||||
{
|
||||
// 删除角色权限关联
|
||||
var rolePerms = _rolePermissions_Repositories.GetList(p => p.RoleId == roleid);
|
||||
foreach (var rp in rolePerms)
|
||||
{
|
||||
await _rolePermissions_Repositories.DeleteAsync(rp.Id);
|
||||
}
|
||||
|
||||
// 删除用户角色关联
|
||||
var userRoles = _userRoles_Repositories.GetList(p => p.RoleId == roleid);
|
||||
foreach (var ur in userRoles)
|
||||
{
|
||||
await _userRoles_Repositories.DeleteAsync(ur.Id);
|
||||
}
|
||||
|
||||
// 删除角色
|
||||
await _roles_Repositories.DeleteAsync(roleid);
|
||||
await InitData("");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -43,6 +43,22 @@
|
||||
</Select>
|
||||
</FormItem>
|
||||
|
||||
<FormItem Label="角色分配" LabelCol="LayoutModel._formItemLayout.LabelCol" WrapperCol="LayoutModel._formItemLayout.WrapperCol">
|
||||
<Select Mode="multiple"
|
||||
@bind-Values="_roleIds"
|
||||
Placeholder="选择角色"
|
||||
TItemValue="string"
|
||||
TItem="string"
|
||||
Size="@AntSizeLDSType.Default">
|
||||
<SelectOptions>
|
||||
@foreach (var role in _allRoles)
|
||||
{
|
||||
<SelectOption TItem="string" TItemValue="string" Value="@role.Id" Label="@role.Name" />
|
||||
}
|
||||
</SelectOptions>
|
||||
</Select>
|
||||
</FormItem>
|
||||
|
||||
<FormItem Label=" " Style="margin-top:32px" WrapperCol="LayoutModel._submitFormLayout.WrapperCol">
|
||||
<Button Type="primary" OnClick="HandleSubmit">
|
||||
保存
|
||||
|
||||
@@ -12,21 +12,34 @@ namespace AntSK.Pages.Setting.User
|
||||
[Parameter]
|
||||
public string UserId { get; set; }
|
||||
[Inject] protected IUsers_Repositories _users_Repositories { get; set; }
|
||||
[Inject] protected IRoles_Repositories _roles_Repositories { get; set; }
|
||||
[Inject] protected IUserRoles_Repositories _userRoles_Repositories { get; set; }
|
||||
[Inject] protected MessageService? Message { get; set; }
|
||||
[Inject] public HttpClient HttpClient { get; set; }
|
||||
|
||||
private Users _userModel = new Users();
|
||||
private string _password = "";
|
||||
IEnumerable<string> _menuKeys;
|
||||
IEnumerable<string> _roleIds;
|
||||
|
||||
private List<MenuDataItem> menuList = new List<MenuDataItem>();
|
||||
private List<Roles> _allRoles = new List<Roles>();
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await base.OnInitializedAsync();
|
||||
|
||||
// 加载所有角色
|
||||
_allRoles = _roles_Repositories.GetList(r => r.IsEnabled);
|
||||
|
||||
if (!string.IsNullOrEmpty(UserId))
|
||||
{
|
||||
_userModel = _users_Repositories.GetFirst(p => p.Id == UserId);
|
||||
_password = _userModel.Password;
|
||||
|
||||
// 加载用户已有的角色
|
||||
var userRoles = _userRoles_Repositories.GetList(p => p.UserId == UserId);
|
||||
_roleIds = userRoles.Select(ur => ur.RoleId);
|
||||
}
|
||||
menuList = (await HttpClient.GetFromJsonAsync<MenuDataItem[]>("data/menu.json")).ToList().Where(p => p.Key != "setting").ToList();
|
||||
_menuKeys = _userModel.MenuRole?.Split(",");
|
||||
@@ -52,6 +65,21 @@ namespace AntSK.Pages.Setting.User
|
||||
}
|
||||
_userModel.Password = PasswordUtil.HashPassword(_userModel.Password);
|
||||
_users_Repositories.Insert(_userModel);
|
||||
|
||||
// 添加用户角色关联
|
||||
if (_roleIds != null)
|
||||
{
|
||||
foreach (var roleId in _roleIds)
|
||||
{
|
||||
_userRoles_Repositories.Insert(new UserRoles
|
||||
{
|
||||
Id = Guid.NewGuid().ToString(),
|
||||
UserId = _userModel.Id,
|
||||
RoleId = roleId,
|
||||
CreateTime = DateTime.Now
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -61,6 +89,28 @@ namespace AntSK.Pages.Setting.User
|
||||
_userModel.Password = PasswordUtil.HashPassword(_userModel.Password);
|
||||
}
|
||||
_users_Repositories.Update(_userModel);
|
||||
|
||||
// 先删除旧的用户角色关联
|
||||
var oldUserRoles = _userRoles_Repositories.GetList(p => p.UserId == UserId);
|
||||
foreach (var ur in oldUserRoles)
|
||||
{
|
||||
_userRoles_Repositories.Delete(ur.Id);
|
||||
}
|
||||
|
||||
// 添加新的用户角色关联
|
||||
if (_roleIds != null)
|
||||
{
|
||||
foreach (var roleId in _roleIds)
|
||||
{
|
||||
_userRoles_Repositories.Insert(new UserRoles
|
||||
{
|
||||
Id = Guid.NewGuid().ToString(),
|
||||
UserId = _userModel.Id,
|
||||
RoleId = roleId,
|
||||
CreateTime = DateTime.Now
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Back();
|
||||
|
||||
@@ -10,6 +10,10 @@ namespace AntSK.Services.Auth
|
||||
{
|
||||
public class AntSKAuthProvider(
|
||||
IUsers_Repositories _users_Repositories,
|
||||
IUserRoles_Repositories _userRoles_Repositories,
|
||||
IRoles_Repositories _roles_Repositories,
|
||||
IRolePermissions_Repositories _rolePermissions_Repositories,
|
||||
IPermissions_Repositories _permissions_Repositories,
|
||||
ProtectedSessionStorage _protectedSessionStore
|
||||
) : AuthenticationStateProvider
|
||||
{
|
||||
@@ -29,13 +33,18 @@ namespace AntSK.Services.Auth
|
||||
new Claim(ClaimTypes.Role, AdminRole)
|
||||
};
|
||||
identity = new ClaimsIdentity(claims, AdminRole);
|
||||
await _protectedSessionStore.SetAsync("UserSession", new UserSession() { UserName = username, Role = AdminRole });
|
||||
await _protectedSessionStore.SetAsync("UserSession", new UserSession()
|
||||
{
|
||||
UserName = username,
|
||||
Role = AdminRole,
|
||||
Roles = new List<string> { AdminRole },
|
||||
Permissions = new List<string>()
|
||||
});
|
||||
NotifyAuthenticationStateChanged(GetAuthenticationStateAsync());
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
string UserRole = "AntSKUser";
|
||||
if (user.IsNull())
|
||||
{
|
||||
return false;
|
||||
@@ -44,13 +53,42 @@ namespace AntSK.Services.Auth
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// 获取用户的角色和权限
|
||||
var userRoles = _userRoles_Repositories.GetList(p => p.UserId == user.Id);
|
||||
var roleIds = userRoles.Select(ur => ur.RoleId).ToList();
|
||||
var roles = _roles_Repositories.GetList(r => roleIds.Contains(r.Id) && r.IsEnabled);
|
||||
|
||||
// 获取角色的权限
|
||||
var rolePermissions = _rolePermissions_Repositories.GetList(rp => roleIds.Contains(rp.RoleId));
|
||||
var permissionIds = rolePermissions.Select(rp => rp.PermissionId).Distinct().ToList();
|
||||
var permissions = _permissions_Repositories.GetList(p => permissionIds.Contains(p.Id));
|
||||
|
||||
// 如果没有角色,使用默认角色
|
||||
string defaultRole = "AntSKUser";
|
||||
var roleList = roles.Any() ? roles.Select(r => r.Code).ToList() : new List<string> { defaultRole };
|
||||
var permissionList = permissions.Select(p => p.Code).ToList();
|
||||
|
||||
// 用户认证成功,创建用户的ClaimsIdentity
|
||||
var claims = new[] {
|
||||
new Claim(ClaimTypes.Name, username),
|
||||
new Claim(ClaimTypes.Role, UserRole)
|
||||
};
|
||||
identity = new ClaimsIdentity(claims, UserRole);
|
||||
await _protectedSessionStore.SetAsync("UserSession", new UserSession() { UserName = username, Role = UserRole });
|
||||
var claims = new List<Claim>
|
||||
{
|
||||
new Claim(ClaimTypes.Name, username)
|
||||
};
|
||||
|
||||
// 添加所有角色到Claims
|
||||
foreach (var role in roleList)
|
||||
{
|
||||
claims.Add(new Claim(ClaimTypes.Role, role));
|
||||
}
|
||||
|
||||
identity = new ClaimsIdentity(claims, roleList.FirstOrDefault() ?? defaultRole);
|
||||
await _protectedSessionStore.SetAsync("UserSession", new UserSession()
|
||||
{
|
||||
UserName = username,
|
||||
Role = roleList.FirstOrDefault() ?? defaultRole,
|
||||
Roles = roleList,
|
||||
Permissions = permissionList
|
||||
});
|
||||
NotifyAuthenticationStateChanged(GetAuthenticationStateAsync());
|
||||
return true;
|
||||
}
|
||||
@@ -68,9 +106,25 @@ namespace AntSK.Services.Auth
|
||||
var userSession = userSessionStorageResult.Success ? userSessionStorageResult.Value : null;
|
||||
if (userSession.IsNotNull())
|
||||
{
|
||||
var claims = new[] {
|
||||
new Claim(ClaimTypes.Name, userSession.UserName),
|
||||
new Claim( ClaimTypes.Role, userSession.Role) };
|
||||
var claims = new List<Claim>
|
||||
{
|
||||
new Claim(ClaimTypes.Name, userSession.UserName)
|
||||
};
|
||||
|
||||
// 添加所有角色到Claims
|
||||
if (userSession.Roles != null && userSession.Roles.Any())
|
||||
{
|
||||
foreach (var role in userSession.Roles)
|
||||
{
|
||||
claims.Add(new Claim(ClaimTypes.Role, role));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 向后兼容,使用单个Role
|
||||
claims.Add(new Claim(ClaimTypes.Role, userSession.Role));
|
||||
}
|
||||
|
||||
identity = new ClaimsIdentity(claims, userSession.Role);
|
||||
}
|
||||
var user = new ClaimsPrincipal(identity);
|
||||
|
||||
@@ -59,6 +59,11 @@
|
||||
"name": "用户管理",
|
||||
"key": "setting.user"
|
||||
},
|
||||
{
|
||||
"path": "/setting/rolelist",
|
||||
"name": "角色管理",
|
||||
"key": "setting.role"
|
||||
},
|
||||
{
|
||||
"path": "/setting/chathistory",
|
||||
"name": "聊天记录",
|
||||
|
||||
Reference in New Issue
Block a user