C#如何优雅的对WinForm窗体应用程序进行权限控制

 更新时间:2022年11月26日 10:46:20   作者:阔活洵信  
经常会出现winfrom页面需要加载权限树,下面这篇文章主要给大家介绍了关于C#如何优雅的对WinForm窗体应用程序进行权限控制的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下

前言

特别复杂特别高大上的系统我还没有机会接触,就我了解的来看,普通的功能权限控制的流程都差不多只有两个过程:

  • 获取当前用户拥有的权限
  • 在界面上对功能入库的可用性或者可见性进行控制

这里说一种在WinForm窗体应用开发时进行权限控制的办法,文章中主要针对上述两个过程的第二步。不过为了说清楚,我先简单说一下我的数据库功能表设计。

数据库

大家的权限数据库好像都差不多,我比较习惯Code First,所以就直接贴数据库对应的对象。记录下功能名称,所属模块,窗体名称,控件名称。权限表里面主要就是记录了用户(角色)ID和功能的对应了,有记录就表示该用户(角色)拥有该功能权限,没有记录就是没有权限。

/// <summary>
/// 系统功能
/// </summary>
[SugarTable("X_FUNCTION", "系统功能")]
public class FUNCTION
{
    [SugarColumn(IsPrimaryKey = true, ColumnDescription = "主键", Length = 50)]
    public string GUID { get; set; }

    /// <summary>
    /// 功能名称
    /// </summary>
    [SugarColumn(ColumnDataType = "NVARCHAR2(30)", ColumnDescription = "功能名称")]
    public string NAME
    {
        get;
        set;
    }

    /// <summary>
    /// 模块ID
    /// </summary>
    [SugarColumn(ColumnDescription = "模块ID", Length = 50)]
    public string MODULEID
    {
        get;
        set;
    }

    /// <summary>
    /// 窗体名称
    /// </summary>
    [SugarColumn(ColumnDescription = "窗体名称", Length = 50)]
    public string FORMNAME
    {
        get;
        set;
    }

    /// <summary>
    /// 控件名称
    /// </summary>
    [SugarColumn(ColumnDescription = "控件名称", Length = 50)]
    public string CONTROLNAME
    {
        get;
        set;
    }
}

如何控制

最简单的方法,就是自己在代码里面把每个功能入口的控件都手动判断一遍,他们的name在不在有权限的功能列表的控件名称里。当然简单很有可能就代表麻烦,有的窗口可能要控制的上百控件,得写上百if-esle,这实在是太不优雅了,如果还有多个窗口的权限需要控制,那就真是灾难了。这个时候反射就可以起到比较好的作用。我们可以创建一个继承自Form的类,在这个类里面检查权限并设置控件是否可用。我使用了DevExpress控件,所以继承自XtraForm。然后只要窗口继承CheckPowerXtraForm,就可以进行权限控制了。

代码中有两个地方需要注意,第一是要等待创建窗口句柄再设置窗口控件的可用性。因为要等待,以及读数据库,所以不能放在主线程里面(写到这里,忽然觉得这个检查权限应该放在FormLoad事件里比较好,不用Thread.Sleep,不过要读数据库,还是不适合放在主线程)。

/// <summary>
/// 检查权限
/// </summary>
public class CheckPowerXtraForm : XtraForm
{
    public CheckPowerXtraForm()
    {
        //不要再主线程运行
        Task.Run(() =>
        {
            CheckPower();
        });
    }
    
    /// <summary>
    /// 检查权限
    /// </summary>
    private async void CheckPower()
    {
        var powerDal = new PowerDAL();
        var functions = await powerDal.GetPowerFunctionsByUserAsync(Global.User.GUID);
        //获取值属于本窗体的权限控件名称
        var formControls = functions.Where(f => f.FORMNAME == this.GetType().Name).Select(f => f.CONTROLNAME).ToList();
        //等待创建窗口句柄
        while (!this.Visible)
        {
            Thread.Sleep(100);
        }
        this.BeginInvoke(new Action(()=>{
            var type = this.GetType();
            var fields = this.GetType().GetFields(BindingFlags.NonPublic|BindingFlags.Instance);
            foreach (var field in fields)
            {
                var value = field.GetValue(this);
                if (value is Control)
                {
                    var control = value as Control;
                    if (!formControls.Contains(control.Name))
                    {
                        control.Enabled = false;
                    }
                }
                else if (value is BarItem)
                {
                    var item = value as BarItem;
                    if (!formControls.Contains(item.Name))
                    {
                        item.Enabled = false;
                    }
                }
                else if (value is ToolStripMenuItem)
                {
                    var item = value as ToolStripMenuItem;
                    if (!formControls.Contains(item.Name))
                    {
                        item.Enabled = false;
                    }
                }
            }
        }));
    }
}

问题

上面的做法有一个问题,窗口里面不是所有控件都需要权限控制的,有的是一些容器性的控件比如Groupbox,有的是一些是个用户就有的功能比如退出登录。按上面代码的做法,只要没有记录的,全部都会设置成不可用。所以我们需要对需要权限控制的做一个标记。有两个办法:

  • 把所有需要控制权限的控件Enabled都事先设置成false,然后有权限的就设置成true。
  • 给需要控制的控件设置一个特性。

下面说说第二种做法。首先定义一个特性,里面什么都不需要写。

/// <summary>
/// 检查权限的特性
/// </summary>
[AttributeUsage(AttributeTargets.Field)]
public class CheckPowerAttribute : Attribute
{
}

然后给需要控制的控件赋予这个特性。

[CheckPowerAttribute]
private DevExpress.XtraBars.BarButtonItem mbbi_exportexcel;
[CheckPowerAttribute]
private DevExpress.XtraBars.BarButtonItem mbbi_exportcad;
[CheckPowerAttribute]
private DevExpress.XtraBars.BarButtonItem mbbi_exportshp;

然后在权限控制代码里只处理具有这个特性的控件。

//~~~
foreach (var field in fields)
{
    var cattributes = field.GetCustomAttributes(typeof(CheckPowerAttribute), false);
    if (cattributes.Length != 0)
    {
        var value = field.GetValue(this);
        if (value is Control)
        {
            var control = value as Control;
            if (!formControls.Contains(control.Name))
            {
                control.Enabled = false;
            }
        }
        else if (value is BarItem)
        {
            var item = value as BarItem;
            if (!formControls.Contains(item.Name))
            {
                item.Enabled = false;
            }
        }
        else if (value is ToolStripMenuItem)
        {
            var item = value as ToolStripMenuItem;
            if (!formControls.Contains(item.Name))
            {
                item.Enabled = false;
            }
        }
    }
}
//~~~

总结

说是优雅,其实自己一边写一边都觉得有不少改进的地方,比如CheckPower()执行的位置,还有设置Enable的时候用反射设置也会简洁很多,如果有更好的改进方案欢迎评论讨论。

到此这篇关于C#如何优雅的对WinForm窗体应用程序进行权限控制的文章就介绍到这了,更多相关C# WinForm窗体应用权限控制内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C#加密知识整合 (AES,MD5,RSA,SHA256)

    C#加密知识整合 (AES,MD5,RSA,SHA256)

    这篇文章主要介绍了c#对于加密的一点整合 (AES,MD5,RSA,SHA256),本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-01-01
  • C#获取USB事件API实例分析

    C#获取USB事件API实例分析

    这篇文章主要介绍了C#获取USB事件API,实例分析了C#操作USB事件的相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-05-05
  • C#集合类用法实例代码详解

    C#集合类用法实例代码详解

    本文通过实例代码给大家介绍了C#集合类用法的相关知识,非常不错,具有参考借鉴价值,需要的朋友可以参考下
    2017-10-10
  • C#使用Clipboard类实现剪贴板功能

    C#使用Clipboard类实现剪贴板功能

    这篇文章介绍了C#使用Clipboard类实现剪贴板功能的方法,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-06-06
  • C#实现windows form拷贝内容到剪贴板的方法

    C#实现windows form拷贝内容到剪贴板的方法

    这篇文章主要介绍了C#实现windows form拷贝内容到剪贴板的方法,涉及C#操作Clipboard的相关技巧,需要的朋友可以参考下
    2015-06-06
  • C#读取配置文件的方法汇总

    C#读取配置文件的方法汇总

    本文给大家介绍的是使用C#读取配置文件的方法,个人给大家总结了6种,余下的以后再更新,有需要的小伙伴可以参考下。
    2015-06-06
  • C# Winform实现捕获窗体最小化、最大化、关闭按钮事件的方法

    C# Winform实现捕获窗体最小化、最大化、关闭按钮事件的方法

    这篇文章主要介绍了C# Winform实现捕获窗体最小化、最大化、关闭按钮事件的方法,可通过重写WndProc来实现,需要的朋友可以参考下
    2014-08-08
  • C#操作ini文件的帮助类

    C#操作ini文件的帮助类

    这篇文章介绍了C#操作ini文件的帮助类,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-04-04
  • C#事件访问器详解

    C#事件访问器详解

    C#事件访问器详细解析。下面示例演示了具有访问器的声明.两个访问器都有叫做value的隐式值参数,它接受实例或静态方法的引用
    2014-01-01
  • 详解C# 不能用于文件名的字符

    详解C# 不能用于文件名的字符

    在 Windows 有一些字符是不能作为文件名,尝试重命名一个文件,输入/ 就可以看到windows 提示的不能作为文件名的字符,那么具体是包括哪些符号不能作为文件名呢?下面小编给大家介绍下
    2018-02-02

最新评论