1420 字
7 分钟
WPF 应用中的权限控制设计:一种完美的实现方案

在开发 WPF 应用时,权限控制是必不可少的功能之一。对于 IT 从业人员来说,如何有效地实现权限管理是每个系统都需要面对的挑战。通常,权限控制设计需要包括用户、角色与功能权限的管理。本文将分享一种简单、易维护、且高效的权限控制设计方案,帮助你快速实现权限管理功能,提升开发效率。

1. 权限管理概述#

在权限控制的基础架构中,通常有三个主要组成部分:

  • 用户(User):代表系统中的每个操作员。
  • 角色(Role):用户所属的角色,不同角色具有不同的权限。
  • 权限(Authorization):定义哪些操作可以由哪些角色执行。

基本功能:#

  1. 角色管理:添加、删除角色。
  2. 权限分配:为角色设置对应的权限。
  3. 用户管理:为用户分配角色以及执行相应操作。

2. 权限管理的实现#

数据模型设计#

在数据库中,我们可以创建用户、角色和权限相关的表。例如,UserInfo 表表示用户信息,RoleInfo 表表示角色信息,AuthorizationInfo 表存储角色与权限的关系。

public class UserLogic
{
internal UserInfo GetUserById(int id) { }
internal void AddOrSaveUser(UserInfo user) { }
internal List<UserInfo> GetDBUsers() { }
internal List<RoleInfo> GetRoles() { }
internal List<AuthorizationInfo> GetAllAuths() { }
internal RoleInfo GetRoleByID(int id) { }
internal List<AuthorizationInfo> GetAuthsByRoleID(int rid) { }
internal void SetAuthsByRoleID(int rid, List<EAuthorizationItem> auths) { }
internal int AddOrSaveRole(RoleInfo ro) { }
internal void DelRole(int id) { }
internal RoleInfo GetRoleByName(string name) { }
}

删除角色#

在删除角色时,需要确保相关的权限和用户关系被正确清理。代码示例如下:

internal void DelRole(int id)
{
using (MyContext db = new MyContext())
{
var existR = db.roles.FirstOrDefault(r => r.ID == id);
db.roles.Remove(existR);
var auths = db.auths.Where(r => r.RoleID == id).ToList();
db.auths.RemoveRange(auths);
var users = db.users.Where(r => r.RoleID == id).ToList();
var defRole = db.roles.FirstOrDefault(r => r.Name == "User");
foreach (var user in users)
{
user.RoleID = defRole.ID;
}
db.SaveChanges();
}
}

设置权限#

当为角色设置权限时,可以将角色当前的权限删除,然后重新添加新的权限:

internal void SetAuthsByRoleID(int rid, List<EAuthorizationItem> auths)
{
using (MyContext db = new MyContext())
{
var existAuths = db.auths.Where(r => r.RoleID == rid).ToList();
db.auths.RemoveRange(existAuths);
List<AuthorizationInfo> besave = new List<AuthorizationInfo>();
foreach (var auth in auths)
{
besave.Add(new AuthorizationInfo()
{
RoleID = rid,
AuthE = auth
});
}
db.auths.AddRange(besave);
db.SaveChanges();
}
}

3. 权限标识设计:使用枚举实现#

权限管理中,我们可以通过固定的字符串来描述各个权限(如 Add_xxInfo, Del_xxInfo 等)。但为了提升系统的可维护性和扩展性,使用枚举类型来描述权限是一个更好的选择。枚举不仅能够提供类型安全,还可以方便地进行代码与数据库之间的转换。

public enum EAuthorizationItem
{
[EnumDescription("打印机或自助机信息更新")]
PrinterOrTerminalUpdate,
[EnumDescription("打印机或自助机删除")]
PrinterOrTerminalDel,
[EnumDescription("数据接口管理")]
DataSourceMgt,
[EnumDescription("用户信息删除")]
UserDel,
[EnumDescription("用户信息更新")]
UserUpdate,
[EnumDescription("权限管理")]
RoleMgt
}

4. WPF 界面与权限绑定#

在 WPF 应用中,我们利用数据绑定(Binding)和命令(Command)来实现权限控制,动态地启用或禁用控件。具体来说,我们在 MenuItem 控件的 IsEnabled 属性中绑定权限标识,并使用 IValueConverter 来转换权限信息与界面控件的状态。

<MenuItem Header="编辑所选项" Name="me_Update" Click="me_Update_Click"
IsEnabled="{Binding UserUpdate, Source={x:Static cd:AuthorizationItemDefine.Default}, Converter={StaticResource auCOnverter}}"></MenuItem>

5. 通过静态类统一管理权限标识#

为了避免重复代码,我们使用一个静态类 AuthorizationItemDefine 来统一管理所有的权限标识。这个类会在用户登录后,存储所有权限标识,并通过 RiseProperty 方法触发界面刷新。

public class AuthorizationItemDefine : PropertyChangedBase
{
public static AuthorizationItemDefine Default { get { return m_Default; } }
private static AuthorizationItemDefine m_Default = new AuthorizationItemDefine();
public void RiseProperty()
{
OnPropertyChanged(() => PrinterOrTerminalUpdate);
OnPropertyChanged(() => PrinterOrTerminalDel);
OnPropertyChanged(() => DataSourceMgt);
OnPropertyChanged(() => UserDel);
OnPropertyChanged(() => UserUpdate);
OnPropertyChanged(() => RoleMgt);
}
public EAuthorizationItem PrinterOrTerminalUpdate { get { return EAuthorizationItem.PrinterOrTerminalUpdate; } }
public EAuthorizationItem PrinterOrTerminalDel { get { return EAuthorizationItem.PrinterOrTerminalDel; } }
public EAuthorizationItem DataSourceMgt { get { return EAuthorizationItem.DataSourceMgt; } }
public EAuthorizationItem UserDel { get { return EAuthorizationItem.UserDel; } }
public EAuthorizationItem UserUpdate { get { return EAuthorizationItem.UserUpdate; } }
public EAuthorizationItem RoleMgt { get { return EAuthorizationItem.RoleMgt; } }
}

6. 权限转换器:IValueConverter#

IValueConverter 用于将界面中的权限标识与当前用户的权限信息进行比较,从而确定控件是否可以启用。例如,在登录时,我们会将用户的权限信息附加到登录信息中,并在界面加载时,通过 Converter 来决定是否启用相关功能。

class AuthConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null) return false;
if (Runtime.Default.loginInfo == null || Runtime.Default.loginInfo.Auths == null) return false;
string machAu = value.ToString();
return Runtime.Default.loginInfo.Auths.Contains(machAu);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}

7. 完整的权限刷新机制#

在用户登录成功后,系统会通过 RiseProperty 方法刷新所有权限,确保界面上能够正确显示用户的权限状态。

private void Click_login(object sender, RoutedEventArgs e)
{
if (vm.Login(passwordBox.Password) == true)
{
dlg_login.Visibility = Visibility.Hidden;
this.uct_Onlines.LoadFirstPage();
AuthorizationItemDefine.Default.RiseProperty();
}
}

8. 总结#

通过以上设计,我们不仅能够在 WPF 应用中灵活地实现权限控制,还能有效地避免重复代码和维护难度。通过使用枚举、静态类以及数据绑定与转换器等 WPF 的核心特性,我们打造了一个清晰、高效且易于扩展的权限管理系统。通过登录时动态加载用户权限,并在界面上通过绑定和转换器自动管理权限状态,我们的应用能够更好地支持多种角色和权限的管理需求。

这种权限控制设计方式不仅适用于 WPF,还可以借鉴到其他类型的应用开发中,极大提高了开发效率和系统的可维护性。

WPF 应用中的权限控制设计:一种完美的实现方案
https://sw.rscclub.website/posts/wpfyzqxgli/
作者
杨月昌
发布于
2022-10-28
许可协议
CC BY-NC-SA 4.0