RuoVea.OmiApi.UserRole
10.0.0.4
dotnet add package RuoVea.OmiApi.UserRole --version 10.0.0.4
NuGet\Install-Package RuoVea.OmiApi.UserRole -Version 10.0.0.4
<PackageReference Include="RuoVea.OmiApi.UserRole" Version="10.0.0.4" />
<PackageVersion Include="RuoVea.OmiApi.UserRole" Version="10.0.0.4" />
<PackageReference Include="RuoVea.OmiApi.UserRole" />
paket add RuoVea.OmiApi.UserRole --version 10.0.0.4
#r "nuget: RuoVea.OmiApi.UserRole, 10.0.0.4"
#:package RuoVea.OmiApi.UserRole@10.0.0.4
#addin nuget:?package=RuoVea.OmiApi.UserRole&version=10.0.0.4
#tool nuget:?package=RuoVea.OmiApi.UserRole&version=10.0.0.4
RuoVea.OmiApi.UserRole
用户角色管理 API 组件 —— 提供用户、角色、用户角色关联的完整 CRUD 服务。
RuoVea.OmiApi.UserRole 是一个开箱即用的用户角色管理系统 NuGet 包,包含系统用户管理(增删改查、密码管理、状态控制、角色授权、登录锁定解除)、系统角色管理(增删改查、状态控制、权限数据隔离)和缓存服务。支持多租户(ITenantEntity)、种子数据初始化、JWT 认证、密码加密/强度校验和数据库表自动迁移。基于 SqlSugar ORM 和 DynamicWebApi,注册即自动生成 RESTful API 端点,支持 MySql / SqlServer / PostgreSQL / SQLite / Oracle 等多种数据库。
目录
概览
功能特性
| 模块 | 功能 |
|---|---|
| 👤 用户管理 | 增删改查、分页查询、密码修改与重置、登录锁定解除、状态启停、角色授权 |
| 🛡️ 角色管理 | 增删改查、分页查询(含权限过滤)、状态设置、级联删除检查 |
| 🔗 用户角色关联管理 | 批量授权用户角色、批量授权角色用户、按用户Id或角色Id删除关联 |
| 💾 缓存服务 | Set/Get/Remove 缓存操作、前缀批量删除、缓存存在性检查、异步缓存代理 |
| 🏢 多租户支持 | SysRole 和 SysUser 实现 ITenantEntity 接口,支持租户数据隔离 |
| 🌱 种子数据 | 预置超级管理员(superAdmin)、系统管理员(admin)、普通用户(ruovea)及对应角色 |
| 🗄️ 多库支持 | MySql、SqlServer、PostgreSQL、SQLite、Oracle、Dm 等 |
| 🧩 自动 API | 实现 IApplicationService 即自动映射为 REST 控制器 |
| 🔐 密码安全 | 用户密码使用 IPasswordServer 加密存储,支持密码强度校验,支持加密/明文双模式 |
| 🌐 i18n 国际化 | 通过 .resx 资源文件提供中文本地化错误/提示信息 |
架构一览
┌──────────────────────────────────────────────────────────────────────┐
│ NuGet Package │
│ RuoVea.OmiApi.UserRole │
├──────────────────────────────────────────────────────────────────────┤
│ Service Layer (4 Services) │
│ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ │
│ │ SysUserService │ │ SysRoleService │ │SysUserRoleService│ │
│ │ · GetPagesAsync │ │ · GetPagesAsync │ │ (内部服务) │ │
│ │ · AddUser │ │ · AddRole │ │ · GetUserRoles │ │
│ │ · UpdateUser │ │ · UpdateRole │ │ · GetRoleUsers │ │
│ │ · DeleteUser │ │ · DeleteRole │ │ · GrantRoles │ │
│ │ · ChangePwd │ │ · SetStatus │ │ · RemoveByUserId│ │
│ │ · ResetPwd │ │ │ └──────────────────┘ │
│ │ · GrantRole │ └──────────────────┘ │
│ │ · UnlockLogin │ │
│ │ · SetStatus │ ┌──────────────────┐ │
│ └──────────────────┘ │ SysCacheService │ │
│ │ · Set/Get/Remove │ │
│ │ · RemoveByPrefix │ │
│ │ · Clear │ │
│ └──────────────────┘ │
├──────────────────────────────────────────────────────────────────────┤
│ Domain Layer (3 Entities) │
│ ┌─────────────────────┐ │
│ │ SysUser │────< SysUserRole >───┐ │
│ │ · Account/Password │ │ │
│ │ · NickName/Phone │ ┌─────────────┐ │
│ │ · IsDisable/Status │ │ SysRole │ │
│ │ · TenantId (多租户) │ │ · Name/Code│ │
│ └─────────────────────┘ │ · Sort │ │
│ │ · IsDisable│ │
│ │ · TenantId │ │
│ └─────────────┘ │
├──────────────────────────────────────────────────────────────────────┤
│ Infrastructure │
│ SqlSugar ORM · DynamicWebApi · ExSugar Repo · JWT Bearer │
│ ExFilter (异常拦截) · ExPws (密码加密) · ExJwtBearer (认证) │
└──────────────────────────────────────────────────────────────────────┘
领域模型 ER 关系
SysUser (1) ────< SysUserRole >──── (1) SysRole
┌────────┐ ┌───────────┐ ┌───────┐
│ Id │───┐ │ Id │ ┌───│ Id │
│ Account│ ├──>│ UserId │ │ │ Name │
│ ... │ │ │ RoleId │<──┘ │ Code │
│TenantId│ │ │ SysUser │ │TenantId│
└────────┘ │ │ SysRole │ └───────┘
│ └───────────┘
│ SysUserRole 是多对多中间表
│ 含 SysUser 和 SysRole 导航属性 (OneToOne)
└── UserId = SysUser.Id (FK)
RoleId = SysRole.Id (FK)
支持的 .NET 版本
| TFM | NuGet 版本 |
|---|---|
net8.0 |
8.0.2.17 |
net10.0 |
10.0.0.3 |
安装
NuGet 包管理器
# .NET 8 项目
Install-Package RuoVea.OmiApi.UserRole -Version 8.0.2.17
# .NET 10 项目
Install-Package RuoVea.OmiApi.UserRole -Version 10.0.0.3
.NET CLI
dotnet add package RuoVea.OmiApi.UserRole --version 8.0.2.17
依赖项
本包依赖以下组件(安装时会自动引入):
| 包名 | 用途 |
|---|---|
RuoVea.ExFilter |
全局异常拦截与模型验证 |
RuoVea.ExJwtBearer |
JWT Bearer 认证配置 |
RuoVea.ExPws |
密码加密与强度校验(IPasswordServer) |
RuoVea.OmiApi.Config |
系统配置管理(DbInitConfig、Swagger等) |
RuoVea.DynamicWebApi |
动态 API 控制器生成 |
RuoVea.ExSugar |
SqlSugar 仓储模式封装 |
30 秒快速开始
1. 配置数据库连接 (appsettings.json)
{
"ConnectionConfigs": [
{
"DbType": "Sqlite",
"ConnectionString": "DataSource=./ruovea.db"
}
],
"Jwt": {
"ValidateIssuerSigningKey": true,
"IssuerSigningKey": "3c1cbc3f546eda35168c3aa3cb91780fbe703f0996c6d123ea96dc85c70bbc0a",
"ValidateIssuer": true,
"ValidIssuer": "SecurityDemo.Authentication.JWT",
"ValidateAudience": true,
"ValidAudience": "jwtAudience",
"ValidateLifetime": true,
"ExpiredTime": 1440,
"ClockSkew": 5
},
"Password": {
"Strength": "Medium"
},
"DbInitConfig": {
"InitTable": true,
"InitSeedData": true
},
"Swagger": {
"ApiVersions": [
{
"Title": "用户角色管理",
"Version": "system"
}
]
}
}
支持的 DbType 值:
MySql、SqlServer、Sqlite、Oracle、PostgreSQL、Dm、Kdbndp、OpenGauss、ClickHouse等。
2. 注册服务 (Program.cs)
// <summary>
// 在 Program.cs 中注册 OmiApi.UserRole 组件服务
// </summary>
var builder = WebApplication.CreateBuilder(args);
// 注册动态 Web API(自动将 Service 映射为 REST 控制器)
builder.Services.AddDynamicWebApi(options =>
{
options.RemoveControllerPostfixes = new List<string> { "AppService", "Service" };
options.RemovePrefix = new List<string> { "get", "post" };
});
// 注册 HttpContext 用户身份
builder.Services.AddHttpContextSetup<AspNetUser>();
// 注册 JWT 认证
builder.Services.AddAuthenticationSetup(IdentifyEnum.Jwt, true);
// 注册 SqlSugar ORM
builder.Services.AddSqlSugarSetup();
// 注册 UserRole 模块服务(默认 Scoped 生命周期)
builder.Services.AddOmiSystemSetup();
// 注册请求日志拦截、统一返回、异常处理
builder.Services
.RequestActionSetup()
.ResultSetup()
.ExceptionSetup();
// 注册 Swagger
builder.Services.AddSwaggerSetup();
// 初始化数据库表结构和种子数据
builder.Services.AddSystemInitSetup();
// 跨域配置
builder.Services.AddCors(option =>
{
option.AddDefaultPolicy(builder =>
{
builder.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod();
});
});
var app = builder.Build();
app.UseCors();
app.UseAuthentication();
app.UseAuthorization();
app.Run();
3. 启动并访问 Swagger
启动项目后,访问 https://localhost:xxxx/swagger,即可看到 "用户角色管理" 分组下的全部 RESTful API 端点。
核心场景
场景一:创建用户并授权角色
// <summary>
// 创建新用户 —— 异步写法。创建成功后,为用户批量授权角色。
// </summary>
public async Task<bool> CreateUserWithRolesAsync(SysUserService userService)
{
// Step 1: 创建用户
var userInput = new AddUserInput
{
Account = "zhangsan",
Password = "P@ssw0rd!2024",
NickName = "张三",
RealName = "张三丰",
Phone = "13800138000",
Email = "zhangsan@example.com",
Sex = Gender.Male,
IsDisable = YesOrNot.N,
Remark = "市场部新员工"
};
var userId = await userService.AddUser(userInput);
if (userId <= 0)
{
return false;
}
// Step 2: 为用户授权角色
await userService.GrantRole(new UserRolesInput
{
UserId = userId,
RoleIds = new List<long> { 2, 3 } // 授权角色 ID 列表
});
return true;
}
// <summary>
// 创建新用户 —— 同步写法。⚠️ 仅推荐在 Console/测试环境使用。
// </summary>
public bool CreateUserWithRoles(SysUserService userService)
{
var userInput = new AddUserInput
{
Account = "zhangsan",
Password = "P@ssw0rd!2024",
NickName = "张三",
Phone = "13800138000"
};
var userId = userService.AddUser(userInput).GetAwaiter().GetResult();
if (userId <= 0) return false;
userService.GrantRole(new UserRolesInput
{
UserId = userId,
RoleIds = new List<long> { 2, 3 }
}).GetAwaiter().GetResult();
return true;
}
创建用户 + 授权角色流程:
Step 1: 创建用户
├─ 校验 Account 唯一性(account_exists 检查)
├─ IPasswordServer 加密密码
└─ INSERT SysUser
Step 2: 授权用户角色
├─ 删除 UserId 的现有角色关联(DELETE SysUserRole)
├─ 检查每个 RoleId 是否存在(record_not_exists)
└─ 批量 INSERT SysUserRole (UserId, RoleId)
场景二:修改密码与重置密码
// <summary>
// 用户自主修改密码 —— 需验证旧密码。
// </summary>
public async Task<bool> ChangeMyPasswordAsync(SysUserService userService)
{
var input = new ChangePwdInput
{
Password = "OldP@ssw0rd",
NewPassword = "NewP@ssw0rd!2024"
};
// 内部校验:
// 1. 旧密码是否正确 (password_error)
// 2. 新旧密码不能相同 (new_password_same_as_old)
// 3. 新密码强度校验(由 IPasswordServer 校验)
// 4. 新密码加密后 UPDATE SysUser.Password
return await userService.ChangePwd(input);
}
// <summary>
// 管理员重置用户密码 —— 无需旧密码验证。
// </summary>
public async Task<bool> ResetUserPasswordAsync(SysUserService userService)
{
var input = new ResetPwdUserInput
{
Id = 1001,
Password = "Default@123456"
};
// 内部操作:
// 1. 检查用户是否存在 (account_not_exists)
// 2. IPasswordServer 加密新密码
// 3. UPDATE SysUser SET Password = 加密后的密码
return await userService.ResetPwd(input);
}
密码修改流程 (ChangePwd):
开始
│
├─ 1. 根据 JWT Token 获取当前登录用户
│ 若未登录 → 抛出认证异常
│
├─ 2. IPasswordServer.Verify(输入的旧密码, 存储的加密密码)
│ 匹配失败 → 抛出 password_error
│
├─ 3. 新密码 == 旧密码?
│ 是 → 抛出 new_password_same_as_old
│
├─ 4. IPasswordServer.ValidateStrength(新密码)
│ 不满足强度要求 → 抛出校验失败
│
└─ 5. UPDATE SysUser SET Password = IPasswordServer.Encrypt(新密码)
│
结束
场景三:用户状态管理与登录解锁
// <summary>
// 设置用户启用/停用状态 —— 含安全保护检查。
// </summary>
public async Task<bool> ToggleUserStatusAsync(SysUserService userService, long userId, bool disable)
{
var input = new UserInput
{
Id = userId,
IsDisable = disable ? YesOrNot.Y : YesOrNot.N
};
// ⚠️ 安全检查:
// 1. prohibit_modify_self_status - 禁止修改本人账号状态
// 2. prohibit_modify_super_admin_status - 禁止修改超级管理员状态
// 3. 检查用户是否存在 (record_not_exists)
return await userService.SetStatus(input);
}
// <summary>
// 解除用户登录锁定 —— 将 LastLoginTime 置空.
// </summary>
public async Task<bool> UnlockUserAsync(SysUserService userService, long userId)
{
var input = new UnlockLoginInput
{
Id = userId
};
// 内部操作:
// 1. 校验用户是否存在
// 2. UPDATE SysUser SET LastLoginTime = NULL
// (某些认证流程会将 LastLoginTime 设为未来时间来实现临时锁定)
return await userService.UnlockLogin(input);
}
场景四:角色管理与权限数据隔离
// <summary>
// 创建角色 —— 数据权限自动隔离。
// 内部自动设置 Creator 为当前登录用户。
// </summary>
public async Task<long> CreateRoleAsync(SysRoleService roleService)
{
var input = new AddRoleInput
{
Name = "内容编辑",
Code = "content_editor",
Sort = 100,
Remark = "负责内容的审核与发布",
IsDisable = YesOrNot.N
};
return await roleService.AddRole(input);
}
// <summary>
// 分页查询角色 —— 非超管/系统管理员只能看到自己创建或已拥有的角色。
// </summary>
public async Task<PageResult<RoleOutput>> SearchRolesAsync(SysRoleService roleService)
{
var param = new PageRoleInput
{
PageNo = 1,
PageSize = 10,
Name = "管理", // 角色名称模糊搜索
IsDisable = YesOrNot.N // 仅启用角色
};
// 权限数据隔离逻辑(内部):
// - 超级管理员 (superAdmin) → 查看所有角色
// - 系统管理员 (admin) → 查看所有角色
// - 普通用户 → 仅查看自己创建的或已拥有的角色
return await roleService.GetPagesAsync(param);
}
// <summary>
// 删除角色 —— 级联检查。
// </summary>
public async Task DeleteRoleAsync(SysRoleService roleService, long roleId)
{
var input = new DeleteRoleInput { Id = roleId };
// ⚠️ 安全检查:
// 1. prohibit_delete_admin - 禁止删除系统管理员角色
// 2. role_has_accounts - 角色下存在关联用户时禁止删除
// 3. record_not_exists - 角色不存在
await roleService.DeleteRole(input);
}
角色删除检查流程:
DELETE 请求
│
├─ 角色是否存在?
│ 否 → 抛出 record_not_exists
│
├─ 是否为系统管理员角色?
│ 是 → 抛出 prohibit_delete_admin
│
├─ 是否有用户关联该角色?
│ SELECT COUNT(*) FROM SysUserRole WHERE RoleId = @id
│ 有 → 抛出 role_has_accounts
│
└─ DELETE SysRole WHERE Id = @id
场景五:缓存服务操作
// <summary>
// 缓存读写操作 —— 异步写法。
// </summary>
public async Task CacheOperationsAsync(SysCacheService cacheService)
{
// 设置缓存(带过期时间)
await cacheService.Set("user:info:1001", new { Name = "张三", Role = "编辑" }, TimeSpan.FromMinutes(30));
// 获取缓存
var cached = await cacheService.GetValue("user:info:1001");
// 检查缓存是否存在
bool exists = await cacheService.Exists("user:info:1001");
// 获取指定前缀的键名集合
var keys = await cacheService.GetKeysByPrefixKey("user:info:");
// 批量删除指定前缀的缓存
await cacheService.RemoveByPrefixKey("user:info:");
// 清除单个缓存
await cacheService.Remove("user:info:1001");
// 清空所有缓存
await cacheService.Clear();
}
// <summary>
// 缓存操作 —— 同步写法。
// ⚠️ 注意:在 ASP.NET 上下文中可能导致死锁,仅推荐在 Console/测试环境使用。
// </summary>
public void CacheOperations(SysCacheService cacheService)
{
cacheService.Set("key", "value", TimeSpan.FromMinutes(10)).GetAwaiter().GetResult();
var value = cacheService.GetValue("key").GetAwaiter().GetResult();
cacheService.Remove("key").GetAwaiter().GetResult();
}
配置选项详解
数据库连接配置 (ConnectionConfigs)
{
"ConnectionConfigs": [
{
"DbType": "Sqlite",
"ConnectionString": "DataSource=./ruovea.db",
"EnableUnderLine": false,
"EnableDiffLog": false,
"IsEncrypt": false,
"DbSecurity": "",
"IsDeleteFilter": true,
"IsUserIdFilter": false,
"IsTenantIdFilter": false,
"CommandTimeOut": 30
}
]
}
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
DbType |
string | 必填 | 数据库类型 |
ConnectionString |
string | 必填 | 连接字符串 |
EnableUnderLine |
bool | false |
驼峰转下划线 |
EnableDiffLog |
bool | false |
启用库表差异日志 |
IsEncrypt |
bool | false |
连接字符串是否加密 |
DbSecurity |
string | "" |
解密密钥(IsEncrypt=true 时使用) |
IsDeleteFilter |
bool | true |
⚠️ 全局软删除过滤(实体需继承 IDeletedEntity) |
IsUserIdFilter |
bool | false |
按创建者过滤(实体需继承 ICreatorFilter 或 EntityBase) |
IsTenantIdFilter |
bool | false |
按租户过滤(实体需继承 ITenantIdFilter) |
CommandTimeOut |
int | 30 |
SQL 命令超时时间(秒) |
表初始化配置 (DbInitConfig)
{
"DbInitConfig": {
"InitTable": true,
"InitSeedData": true
}
}
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
InitTable |
bool | false |
启动时自动检查并创建缺失的数据表(CodeFirst) |
InitSeedData |
bool | false |
是否写入种子数据(超级管理员、系统管理员、普通用户及对应角色) |
❗ 性能提醒:
AddSystemInitSetup在后台执行表检查和种子数据写入。生产环境首次启动后建议将InitTable和InitSeedData设为false,避免每次启动都执行IsAnyTable检查。
JWT 认证配置 (Jwt)
{
"Jwt": {
"ValidateIssuerSigningKey": true,
"IssuerSigningKey": "your-secret-key-at-least-16-chars",
"ValidateIssuer": true,
"ValidIssuer": "SecurityDemo.Authentication.JWT",
"ValidateAudience": true,
"ValidAudience": "jwtAudience",
"ValidateLifetime": true,
"ExpiredTime": 1440,
"ClockSkew": 5
}
}
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
ValidateIssuerSigningKey |
bool | true |
是否验证密钥 |
IssuerSigningKey |
string | 必填 | ⚠️ 签名密钥,长度须大于16字符 |
ValidateIssuer |
bool | true |
是否验证签发方 |
ValidIssuer |
string | — | 签发方标识 |
ValidateAudience |
bool | true |
是否验证签收方 |
ValidAudience |
string | — | 签收方标识 |
ValidateLifetime |
bool | true |
是否验证过期时间 |
ExpiredTime |
long | 1440 |
Token 过期时间(分钟),默认 24 小时 |
ClockSkew |
long | 5 |
过期时间容错值(秒) |
密码配置 (Password)
{
"Password": {
"Strength": "Medium",
"Encrypted": true
}
}
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
Strength |
string | Medium |
密码强度要求(Low / Medium / High) |
Encrypted |
bool | true |
是否启用密码加密存储(false 时明文存储) |
⚠️ 安全提醒:
Encrypted设置为false时密码以明文存储,仅建议在开发环境使用。生产环境务必启用加密。
DI 注册配置
// <summary>
// AddOmiSystemSetup —— 三种重载,适应不同配置来源。
// 注册服务: JWT、密码配置、SysCacheService、SysRoleService、SysUserRoleService、
// SysUserService、IPasswordServer
// </summary>
// 重载 1:自动从全局 AppSettings.Configuration 读取
builder.Services.AddOmiSystemSetup();
// 重载 2:传入自定义 IConfiguration
builder.Services.AddOmiSystemSetup(configuration.GetSection("MyUserRole"));
// 重载 3:通过 Action 委托配置
builder.Services.AddOmiSystemSetup(options =>
{
options.InitTable = true;
options.InitSeedData = true;
});
// 自定义服务生命周期
builder.Services.AddOmiSystemSetup(ServiceLifetime.Singleton);
// 初始化数据库表结构(SysRole / SysUser / SysUserRole)
builder.Services.AddSystemInitSetup();
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
serviceLifetime |
ServiceLifetime |
Scoped |
注册 4 个服务的生命周期 |
config |
IConfiguration |
— | 自定义配置节 |
config (Action) |
Action<DbInitConfig> |
— | 代码内配置 |
⚠️ 线程安全: 切换为
Singleton生命周期时,确保注入的SugarRepository<T>和ISqlSugarClient本身支持并发访问。SqlSugar 的SqlSugarClient是线程安全的,但仓储的某些操作依赖请求上下文(如Creator自动填充、ICurrentUser身份解析),单例模式下可能导致用户信息串扰。
种子数据说明
当 InitSeedData = true 时,AddSystemInitSetup 会写入以下预置数据:
| 角色 | Code | 说明 |
|---|---|---|
| 超级管理员 | superAdmin |
拥有系统全部权限 |
| 系统管理员 | admin |
拥有管理权限 |
| 用户 | Account | 默认密码 | 关联角色 | 说明 |
|---|---|---|---|---|
| 超级管理员 | superAdmin |
由 IPasswordServer 加密 |
superAdmin |
系统最高权限用户 |
| 系统管理员 | admin |
由 IPasswordServer 加密 |
admin |
日常管理用户 |
| 普通用户 | ruovea |
由 IPasswordServer 加密 |
— | 普通业务用户 |
API 接口速览
所有接口自动归入 Swagger "system" 分组,默认路由前缀由 DynamicWebApi 配置决定。
SysUserService — 用户管理
| HTTP | 方法 | 说明 |
|---|---|---|
| GET | GetPagesAsync |
分页查询用户列表 |
| GET | UserList |
获取用户列表 |
| GET | GetAllAsync |
获取全部用户简要列表(仅 ID、账号、姓名) |
| GET | GetBaseInfo |
查看用户基本信息 |
| GET | GetOwnRoleList |
获取用户拥有角色集合 |
| POST | AddUser |
增加用户(自动去重 Account、加密密码) |
| PUT | UpdateUser |
更新用户信息 |
| PUT | UpdateBaseInfo |
更新用户基本信息 |
| PUT | SetStatus |
设置用户状态(启停用) |
| DELETE | DeleteUser |
删除用户(安全校验:禁止删除自己、禁止删除超管) |
| POST | GrantRole |
授权用户角色(先删后插) |
| POST | ChangePwd |
修改当前用户密码(需验证旧密码) |
| POST | ResetPwd |
重置用户密码(管理员操作,无需旧密码) |
| POST | UnlockLogin |
解除登录锁定 |
SysRoleService — 角色管理
| HTTP | 方法 | 说明 |
|---|---|---|
| GET | GetPagesAsync |
分页查询角色列表(含权限数据隔离) |
| GET | GetList |
获取角色列表 |
| POST | AddRole |
增加角色(Name/Code 唯一性校验) |
| PUT | UpdateRole |
更新角色信息 |
| PUT | SetStatus |
设置角色状态(启停用) |
| DELETE | DeleteRole |
删除角色(安全校验:禁止删除管理员角色、检查关联用户) |
SysUserRoleService — 用户角色关联(内部服务)
| HTTP | 方法 | 说明 |
|---|---|---|
| — | (内部调用) | 获取用户角色列表 |
| — | (内部调用) | 获取角色下的用户列表 |
| — | (内部调用) | 批量授权用户角色(先删后插) |
| — | (内部调用) | 按用户 Id 删除关联 |
| — | (内部调用) | 按角色 Id 删除关联 |
此服务为内部服务,不对外暴露 HTTP 端点,由
SysUserService和SysRoleService调用。
SysCacheService — 缓存管理
| HTTP | 方法 | 说明 |
|---|---|---|
| GET | GetValue |
根据键名获取缓存值 |
| GET | GetKeysByPrefixKey |
根据键名前缀获取键名集合 |
| DELETE | Remove |
删除指定缓存 |
| DELETE | RemoveByPrefixKey |
根据键名前缀批量删除缓存 |
| DELETE | Clear |
清空所有缓存 |
错误处理与日志
错误码速查
组件内部使用 i18n 国际化资源管理错误信息,支持中文本地化:
| 错误码 | 含义 | 触发场景 |
|---|---|---|
account_exists |
账号已存在 | 创建用户时 Account 重复 |
account_not_exists |
账号不存在 | 根据 Account 查询用户时无匹配记录 |
data_exists |
数据已存在 | 创建重复的角色名称或编码 |
dict_status_error |
字典状态错误 | 字典数据状态异常 |
illegal_operation_self |
非法操作,禁止删除自己 | 用户尝试删除自身账号 |
new_password_same_as_old |
新密码不能与旧密码相同 | 修改密码时新旧密码一致 |
password_error |
旧密码输入错误 | 修改密码时旧密码验证失败 |
prohibit_delete_admin |
禁止删除系统管理员角色 | 尝试删除 admin 角色 |
prohibit_delete_super_admin |
禁止删除超级管理员 | 尝试删除 superAdmin 用户 |
prohibit_modify_self_status |
禁止修改本人账号状态 | 用户尝试启用/停用自身账号 |
prohibit_modify_super_admin_status |
禁止修改超级管理员状态 | 尝试修改 superAdmin 的状态 |
record_not_exists |
记录不存在 | 根据 ID 查询/更新时记录缺失 |
role_has_accounts |
此角色下面存在账号禁止删除 | 删除角色时有关联用户 |
no_permission |
没有权限 | 越权操作 |
organization_exists |
已有相同组织机构,编码或名称相同 | 机构重名 |
organization_has_users |
该机构下有用户禁止删除 | 删除机构时有关联用户 |
position_exists |
已存在同名或同编码职位 | 职位重名 |
position_has_users |
该职位下有用户禁止删除 | 删除职位时有关联用户 |
position_not_exists |
职位不存在 | 职位查询无匹配 |
异常处理示例
// <summary>
// 安全创建用户 —— 捕获账号重复、参数验证和密码强度异常。
// </summary>
public async Task<(bool Success, string Message)> SafeCreateUserAsync(
SysUserService userService, AddUserInput input)
{
try
{
var result = await userService.AddUser(input);
return (result > 0, "用户创建成功");
}
catch (ArgumentException ex) when (ex.Message.Contains("account_exists"))
{
// 账号已存在
return (false, $"账号 '{input.Account}' 已被注册");
}
catch (ArgumentException ex)
{
// 其他业务校验失败
return (false, $"业务校验失败: {ex.Message}");
}
catch (AggregateException ex)
{
// 字段级验证失败(密码强度、必填字段等)
return (false, $"字段验证失败: {ex.Message}");
}
}
// <summary>
// 安全删除角色 —— 捕获级联检查异常。
// </summary>
public async Task<(bool Success, string Message)> SafeDeleteRoleAsync(
SysRoleService roleService, long roleId)
{
try
{
await roleService.DeleteRole(new DeleteRoleInput { Id = roleId });
return (true, "角色删除成功");
}
catch (ArgumentException ex) when (ex.Message.Contains("prohibit_delete_admin"))
{
return (false, "系统管理员角色禁止删除");
}
catch (ArgumentException ex) when (ex.Message.Contains("role_has_accounts"))
{
return (false, "该角色下存在关联用户,请先解除所有用户授权后再删除");
}
catch (Exception ex)
{
return (false, $"删除失败: {ex.Message}");
}
}
// <summary>
// 同步写法 —— 安全修改用户状态。
// ⚠️ 仅推荐在非 ASP.NET 上下文使用。
// </summary>
public (bool Success, string Message) SafeSetUserStatus(SysUserService userService, long userId, bool disable)
{
try
{
userService.SetStatus(new UserInput
{
Id = userId,
IsDisable = disable ? YesOrNot.Y : YesOrNot.N
}).GetAwaiter().GetResult();
return (true, disable ? "用户已停用" : "用户已启用");
}
catch (Exception ex)
{
return (false, ex.Message);
}
}
日志集成
组件不直接输出日志,依赖调用方集成的日志框架。推荐在 Program.cs 中配置 Serilog 或 NLog 来捕获:
// SqlSugar 的 SQL 日志可通过 AOP 事件捕获
builder.Services.AddSqlSugarSetup(); // 内部配置了 SQL 执行日志
// ExFilter 的全局异常拦截会自动记录异常日志
builder.Services.RequestActionSetup() // 请求日志拦截
.ExceptionSetup(); // 异常捕获与记录
版本迁移指南
从 8.0.2.x 升级到 10.0.0.x
| 变更项 | 说明 |
|---|---|
| TFM 升级 | net8.0 → net10.0,需同步升级所有依赖包到 10.0.* 版本 |
| 包版本对齐 | RuoVea.ExFilter、RuoVea.ExJwtBearer、RuoVea.ExPws、RuoVea.OmiApi.Config、RuoVea.DynamicWebApi、RuoVea.ExSugar 均需升至对应 10.0.* |
| API 兼容 | 所有公开 API 向后兼容,无需修改业务代码 |
| 数据库 | 表结构无变更,无需执行迁移脚本 |
| 密码加密 | IPasswordServer 接口不变,加密算法向后兼容 |
API 变更历史
| 版本 | 变更 |
|---|---|
8.0.2.17 |
稳定版本 |
8.0.2.16 |
修复多字段查询时 SqlSugar 因重复参数 @value 键报错的问题 |
8.0.2.15 |
组件版本升级,图表数据缓存 |
8.0.2.14 |
表结构初始化处理 |
| 更早版本 | 初始发布 |
常见问题
Q: 如何切换数据库?
修改 appsettings.json 中的 DbType 和 ConnectionString,然后重新运行。AddSystemInitSetup 会自动为新数据库创建表结构。
// MySql 示例
{ "DbType": "MySql", "ConnectionString": "Server=localhost;Database=ruovea;Uid=root;Pwd=123456;" }
// SqlServer 示例
{ "DbType": "SqlServer", "ConnectionString": "Server=.;Database=ruovea;Trusted_Connection=True;" }
// PostgreSQL 示例
{ "DbType": "PostgreSQL", "ConnectionString": "Host=localhost;Database=ruovea;Username=postgres;Password=123456;" }
Q: 如何自定义 API 路由前缀?
在 AddDynamicWebApi 中配置 DefaultApiPrefix:
builder.Services.AddDynamicWebApi(options =>
{
options.DefaultApiPrefix = "/openapi/api";
options.RemoveControllerPostfixes = new List<string> { "AppService", "Service" };
options.RemovePrefix = new List<string> { "get", "post" };
});
Q: 如何实现多租户数据隔离?
SysUser 和 SysRole 实体实现了 ITenantEntity 接口。在 ConnectionConfigs 中启用 IsTenantIdFilter: true,SqlSugar 会自动在查询中追加 TenantId 过滤条件。同时需要在 ICurrentUser 实现中返回当前租户 ID。
{
"ConnectionConfigs": [
{
"DbType": "MySql",
"ConnectionString": "...",
"IsTenantIdFilter": true
}
]
}
Q: ⚠️ 种子数据的默认密码是什么?如何修改?
种子数据中所有用户的密码均使用 IPasswordServer 加密后写入,默认密码由配置中的 Password 配置节控制。如需修改种子用户的默认密码,请修改 AddSystemInitSetup 初始化逻辑中传入的密码明文,或在初始化后通过 ResetPwd 接口重置。
Q: ❗ 为什么 GetPagesAsync 返回的角色列表与预期不符?
角色查询会自动执行权限数据隔离:
- 超级管理员(
superAdmin)和系统管理员(admin)可以查看所有角色 - 普通用户只能查看自己创建的或已拥有的角色
如果登录用户不是超管/系统管理员,查询结果为当前用户权限范围内的角色,并非全部角色。
Q: ChangePwd 和 ResetPwd 有什么区别?
| 方法 | 使用场景 | 是否需要旧密码 | 权限要求 |
|---|---|---|---|
ChangePwd |
用户自主修改密码 | 需要 | 需要登录(JWT Token) |
ResetPwd |
管理员重置他人密码 | 不需要 | 管理员权限 |
Q: 删除用户/角色时被阻止怎么办?
组件内置了安全保护检查:
- 删除用户被阻止:检查是否为
prohibit_delete_super_admin(禁止删除超管)或illegal_operation_self(禁止删除自己) - 删除角色被阻止:检查是否为
prohibit_delete_admin(禁止删除管理员角色)或role_has_accounts(角色下有关联用户)
对于 role_has_accounts,请先通过 SysUserRoleService 解除所有用户与角色的关联,再执行角色删除。
Q: 缓存服务的底层实现是什么?
SysCacheService 是基于 ICacheService(SqlSugar 提供的缓存抽象)实现的,底层可使用 Redis、MemoryCache 或自定义缓存提供程序。缓存键名建议使用 : 分隔的命名空间前缀(如 user:info:1001、role:list),便于通过 RemoveByPrefixKey 批量清理。
许可证
本项目基于 Apache 2.0 License 开源发布。
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- RuoVea.DynamicWebApi (>= 10.0.0)
- RuoVea.ExFilter (>= 10.0.0.6)
- RuoVea.ExJwtBearer (>= 10.0.0.5)
- RuoVea.ExPws (>= 10.0.0.4)
- RuoVea.ExSugar (>= 10.0.0.8)
- RuoVea.OmiApi.Config (>= 10.0.0.4)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on RuoVea.OmiApi.UserRole:
| Package | Downloads |
|---|---|
|
RuoVea.OmiUserRole
用户角色管理 |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 10.0.0.4 | 95 | 6/26/2026 |
| 10.0.0.3 | 112 | 6/24/2026 |
| 10.0.0.2 | 122 | 5/28/2026 |
| 10.0.0.1 | 116 | 3/23/2026 |
| 10.0.0 | 131 | 1/27/2026 |
| 9.0.0.2 | 128 | 5/28/2026 |
| 9.0.0.1 | 122 | 3/23/2026 |
| 9.0.0 | 142 | 1/27/2026 |
| 8.0.2.18 | 98 | 6/26/2026 |
| 8.0.2.17 | 120 | 6/24/2026 |
| 8.0.2.16 | 119 | 5/28/2026 |
| 8.0.1.15 | 129 | 3/23/2026 |
| 8.0.1.14 | 143 | 1/27/2026 |
| 8.0.1.13 | 140 | 1/13/2026 |
| 7.0.2.16 | 120 | 5/28/2026 |
| 7.0.1.15 | 128 | 3/23/2026 |
| 7.0.1.14 | 147 | 1/27/2026 |
| 6.0.2.16 | 122 | 5/28/2026 |
| 6.0.2.15 | 137 | 3/23/2026 |
| 6.0.2.14 | 149 | 1/27/2026 |