在工业控制领域摸爬滚打这些年,我发现权限管理系统就像车间的电路总闸——平时没人注意它的存在,可一旦出问题,整个产线都得停摆。今天要拆解的这套基于WPF+.NET6+SqlSugar的权限管理系统,正是我在三个不同智能制造项目中验证过的实战方案。
这个系统最显著的特点是采用了"客户端-服务端"双模式架构。在局域网环境下,WPF客户端可以直接连接数据库操作,响应时间能控制在100毫秒以内;当需要互联网部署时,只需切换成WebAPI通信模式,通过Nginx配置HTTPS反向代理即可。这种灵活性对于需要同时满足内网高效操作和外网远程管理的制造企业特别实用。
选择WPF作为客户端框架主要基于三个实际考量:
特别值得一提的是,我们使用了DevExpress的GridControl来展示用户数据。这个控件支持动态列生成、实时数据更新等特性,配合ObservableCollection集合,数据变化会自动反映到界面。下面是典型的用户列表XAML实现:
xml复制<dxg:GridControl ItemsSource="{Binding Users}"
AutoGenerateColumns="None"
EnableSmartColumnsGeneration="True">
<dxg:GridControl.Columns>
<dxg:GridColumn FieldName="Account" Header="账号" Width="120"/>
<dxg:GridColumn FieldName="RealName" Header="姓名" Width="100"/>
<dxg:GridColumn FieldName="Department.Name" Header="部门" Width="150"/>
</dxg:GridControl.Columns>
</dxg:GridControl>
服务端采用.NET6的最小API设计,主要处理三类核心功能:
权限校验的核心是这个自定义的授权过滤器:
csharp复制public class PermissionFilter : IAsyncAuthorizationFilter
{
public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
{
var endpoint = context.HttpContext.GetEndpoint();
if (endpoint?.Metadata.GetMetadata<IAllowAnonymous>() != null)
return;
var token = context.HttpContext.Request.Headers["Authorization"];
if (string.IsNullOrEmpty(token))
{
context.Result = new JsonResult(new { Code = 401 }) { StatusCode = 401 };
return;
}
var permissionCode = endpoint?.Metadata.GetMetadata<PermissionAttribute>()?.Code;
if (!await _permissionService.ValidateAsync(token, permissionCode))
{
context.Result = new JsonResult(new { Code = 403 }) { StatusCode = 403 };
}
}
}
相比Entity Framework,SqlSugar在工控系统中有几个不可替代的优势:
下面是典型的用户分页查询实现:
csharp复制public PagedList<User> GetUsers(UserQueryDto dto)
{
return _db.Queryable<User>()
.WhereIF(!string.IsNullOrEmpty(dto.Keyword),
u => u.Name.Contains(dto.Keyword) || u.Account.Contains(dto.Keyword))
.WhereIF(dto.DepartmentId.HasValue, u => u.DepartmentId == dto.DepartmentId)
.OrderBy(u => u.CreateTime, OrderByType.Desc)
.ToPagedList(dto.PageIndex, dto.PageSize);
}
权限管理最复杂的部分莫过于树形结构的动态生成。我们采用递归算法构建权限树,并加入了内存缓存优化:
csharp复制public List<PermissionNode> GetPermissionTree()
{
return _cache.GetOrCreate("PermissionTree", entry =>
{
entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(30);
var allPermissions = _db.Queryable<Permission>().ToList();
return BuildTree(Guid.Empty, allPermissions);
});
}
private List<PermissionNode> BuildTree(Guid parentId, List<Permission> all)
{
return all.Where(p => p.ParentId == parentId)
.Select(p => new PermissionNode
{
Id = p.Id,
Name = p.Name,
Children = BuildTree(p.Id, all)
}).ToList();
}
通过SignalR实现了权限变更的实时推送:
csharp复制public class PermissionHub : Hub
{
public async Task Subscribe(string userId)
{
await Groups.AddToGroupAsync(Context.ConnectionId, userId);
}
}
// 服务端发送通知
await _hubContext.Clients.Group(userId).SendAsync("PermissionChanged");
针对工业现场的特殊需求,我们增加了以下功能:
根据客户网络环境提供两种部署模式:
| 部署类型 | 连接方式 | 适用场景 | 响应时间 |
|---|---|---|---|
| 直连模式 | WPF -> 数据库 | 局域网环境 | <100ms |
| 服务模式 | WPF -> WebAPI -> 数据库 | 互联网环境 | 300-500ms |
查询优化:
WithCache方法缓存常用数据批处理:
csharp复制// 批量插入性能对比
_db.Fastest<User>().BulkInsert(users); // 比普通Insert快8-10倍
内存管理:
现象:修改权限后,部分客户端未及时更新
解决方案:
典型代码处理:
csharp复制public async Task DeleteRole(Guid roleId)
{
try
{
await _db.TransactionAsync(async () =>
{
await _db.Deleteable<UserRole>().Where(ur => ur.RoleId == roleId).ExecuteCommandAsync();
await _db.Deleteable<Role>().Where(r => r.Id == roleId).ExecuteCommandAsync();
});
}
catch (SqlSugarException ex) when (ex.Message.Contains("FK_"))
{
throw new BusinessException("请先解除该角色与用户的关联");
}
}
优化方案:
根据在汽车制造、电子装配等场景的实施经验,建议从以下几个方向进行扩展:
设备权限集成:
csharp复制public class DevicePermission
{
public Guid DeviceId { get; set; }
public List<Guid> AllowedRoles { get; set; }
}
审批工作流:
可视化配置:
这套系统在多个客户现场的运行数据表明,在200并发用户场景下,权限校验的平均响应时间为87ms,99%的请求能在200ms内完成。对于准备自研权限系统的团队来说,这套代码提供了经过验证的基础架构和工控场景的特殊处理方案。