1. 项目背景与核心价值
这套基于WPF+.NET 6 WebAPI+SqlSugar ORM的权限管理平台源码,是我在去年为某中型企业实施内部管理系统时沉淀的技术方案。当时客户需要同时满足C/S架构的桌面端操作体验和B/S架构的移动办公需求,还要兼顾开发效率与系统性能。经过多轮技术选型对比,最终确定了这个技术组合方案。
现在把完整源码开放出来,是因为发现很多.NET开发者面临类似的权限系统开发需求时,要么选择重造轮子耗费大量时间,要么使用过于臃肿的商业框架。这套方案经过实际项目验证,具备以下核心优势:
- 权限粒度控制到按钮级别
- 支持多终端统一认证
- 完整的功能模块包括:用户/角色/菜单管理、操作日志、数据权限过滤
- 采用最新.NET 6技术栈
- 使用轻量级ORM框架SqlSugar
2. 技术架构详解
2.1 整体架构设计
系统采用典型的三层架构:
code复制Presentation Layer (WPF客户端)
↓
Business Layer (WebAPI服务端)
↓
Data Access Layer (SqlSugar ORM)
这种分层设计实现了前后端完全解耦,客户端通过HttpClient调用WebAPI接口,服务端返回统一格式的JSON数据。特别适合需要同时支持桌面端和移动端的场景。
2.2 核心技术选型分析
WPF客户端选择理由:
- 数据绑定和MVVM模式天然适合管理系统开发
- 相比WinForm更现代化的UI体验
- 支持硬件加速的复杂界面渲染
- 可通过XAML灵活定制界面
.NET 6 WebAPI优势:
- 内置依赖注入容器
- 更高效的JSON序列化
- 支持Minimal API简化代码
- 跨平台部署能力
SqlSugar ORM特点:
- 国产ORM中性能第一梯队
- 类似EF Core的LINQ语法
- 更简洁的API设计
- 完善的文档和社区支持
3. 核心功能实现
3.1 权限控制系统
权限控制是整套系统的核心,采用RBAC(基于角色的访问控制)模型,包含以下关键设计:
数据库表结构:
sql复制CREATE TABLE [User] (
Id INT PRIMARY KEY,
UserName NVARCHAR(50),
Password NVARCHAR(100) -- 实际存储的是加盐哈希
);
CREATE TABLE [Role] (
Id INT PRIMARY KEY,
RoleName NVARCHAR(50)
);
CREATE TABLE [UserRole] (
UserId INT,
RoleId INT,
PRIMARY KEY (UserId, RoleId)
);
CREATE TABLE [Menu] (
Id INT PRIMARY KEY,
ParentId INT,
MenuName NVARCHAR(50),
Url NVARCHAR(255),
Icon NVARCHAR(50),
ButtonCode NVARCHAR(50) -- 按钮权限标识
);
CREATE TABLE [RoleMenu] (
RoleId INT,
MenuId INT,
ButtonAuth NVARCHAR(MAX), -- 存储JSON格式的按钮权限
PRIMARY KEY (RoleId, MenuId)
);
权限验证流程:
- 用户登录获取JWT Token
- 前端路由守卫检查菜单权限
- 按钮渲染时检查ButtonCode权限
- API接口通过自定义ActionFilter验证
3.2 动态菜单生成
WPF客户端通过以下代码动态加载菜单:
csharp复制private void LoadMenus()
{
var menus = _apiService.Get<List<MenuDto>>("/api/menu/usermenus");
foreach(var menu in menus.Where(m => m.ParentId == 0))
{
var parentItem = new MenuItem {
Header = menu.MenuName,
Icon = new Image { Source = new BitmapImage(new Uri(menu.Icon)) }
};
AddChildMenus(parentItem, menus, menu.Id);
MainMenu.Items.Add(parentItem);
}
}
private void AddChildMenus(MenuItem parent, List<MenuDto> allMenus, int parentId)
{
foreach(var child in allMenus.Where(m => m.ParentId == parentId))
{
var childItem = new MenuItem {
Header = child.MenuName,
Command = new RelayCommand(() => NavigateTo(child.Url))
};
parent.Items.Add(childItem);
}
}
4. 关键代码解析
4.1 JWT认证实现
服务端配置JWT认证:
csharp复制builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = builder.Configuration["Jwt:Issuer"],
ValidAudience = builder.Configuration["Jwt:Audience"],
IssuerSigningKey = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"]))
};
});
登录接口生成Token:
csharp复制[HttpPost("login")]
public IActionResult Login([FromBody] LoginDto dto)
{
// 验证用户名密码...
var claims = new[]
{
new Claim(ClaimTypes.Name, user.UserName),
new Claim(ClaimTypes.Role, string.Join(",", user.Roles))
};
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(
_config["Jwt:Key"]));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken(
issuer: _config["Jwt:Issuer"],
audience: _config["Jwt:Audience"],
claims: claims,
expires: DateTime.Now.AddMinutes(30),
signingCredentials: creds);
return Ok(new { token = new JwtSecurityTokenHandler().WriteToken(token) });
}
4.2 SqlSugar数据操作
定义实体和仓储基类:
csharp复制[SugarTable("User")]
public class User
{
[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
public int Id { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
}
public class Repository<T> where T : class, new()
{
protected SqlSugarScope _db;
public Repository(ISqlSugarClient db)
{
_db = (SqlSugarScope)db;
}
public async Task<List<T>> GetList(Expression<Func<T, bool>> where)
{
return await _db.Queryable<T>().Where(where).ToListAsync();
}
// 其他CRUD方法...
}
5. 部署与使用指南
5.1 开发环境准备
必要工具:
- Visual Studio 2022 (17.0+)
- .NET 6 SDK
- SQL Server 2019 (或更高版本)
- Postman (用于API测试)
数据库配置步骤:
- 执行源码中的SQL脚本创建数据库
- 修改appsettings.json中的连接字符串
- 运行EF Core迁移命令更新数据库结构
5.2 项目启动顺序
- 首先启动WebAPI项目
- 然后启动WPF客户端
- 默认管理员账号:admin/123456
6. 扩展与二次开发
6.1 常见扩展场景
多租户支持方案:
- 在用户表添加TenantId字段
- 修改仓储基类自动添加租户过滤
- 实现租户管理界面
数据权限控制:
- 在角色表添加DataScope字段
- 实现数据过滤拦截器
- 根据用户角色动态拼接查询条件
6.2 性能优化建议
数据库层面:
- 为常用查询字段添加索引
- 使用SqlSugar的二级缓存
- 对大表进行分库分表
API层面:
- 实现响应缓存
- 使用压缩中间件
- 启用HTTP/2协议
7. 常见问题排查
7.1 权限失效问题
症状: 登录后某些菜单或按钮仍然不可见
排查步骤:
- 检查JWT Token中的角色信息是否正确
- 确认数据库RoleMenu表有对应记录
- 查看浏览器控制台是否有API请求错误
7.2 数据库连接问题
错误信息: "Connection Timeout Expired"
解决方案:
- 检查连接字符串中的服务器地址
- 确认SQL Server已启用远程连接
- 在连接字符串中添加Connect Timeout=30
这套源码我已经在实际项目中迭代优化了三个版本,最大的体会是权限系统要尽早确定数据权限的设计方案,不然后期改造会很痛苦。另外建议在开发企业管理系统时,一定要把操作日志功能做完善,这对后期排查问题非常有帮助。