Winform開發(fā)框架之字段權(quán)限控制

在我的很多Winform開發(fā)項(xiàng)目中(包括混合框架的項(xiàng)目),統(tǒng)一采用了權(quán)限管理模塊來進(jìn)行各種權(quán)限的控制,包括常規(guī)的功能權(quán)限(按鈕、菜單權(quán)限)、數(shù)據(jù)權(quán)限(記錄的權(quán)限),另外還可以進(jìn)行字段級別的字段權(quán)限控制,字段權(quán)限是我們在一些對權(quán)限要求比較嚴(yán)格的系統(tǒng)里面涉及到的,可以對部分用戶隱藏一些敏感的信息。本篇主要介紹字段權(quán)限的控制思路及實(shí)現(xiàn)機(jī)制,以便大家對這個字段權(quán)限的控制有一個直觀的了解。
如果需要對權(quán)限系統(tǒng)的功能進(jìn)行一定的了解,可以先回顧下我前面的文章《Winform開發(fā)框架之權(quán)限管理系統(tǒng)功能介紹》、《如何在應(yīng)用系統(tǒng)中實(shí)現(xiàn)數(shù)據(jù)權(quán)限的控制功能》、《如何在應(yīng)用系統(tǒng)中實(shí)現(xiàn)數(shù)據(jù)權(quán)限的控制功能(2)》,以及《Winform開發(fā)框架之權(quán)限管理系統(tǒng)改進(jìn)的經(jīng)驗(yàn)總結(jié)(1)-TreeListLookupEdit控件的使用》、《Winform開發(fā)框架之權(quán)限管理系統(tǒng)改進(jìn)的經(jīng)驗(yàn)總結(jié)(2)-用戶選擇界面的設(shè)計(jì)》、《Winform開發(fā)框架之權(quán)限管理系統(tǒng)改進(jìn)的經(jīng)驗(yàn)總結(jié)(4)--用戶分級管理》等文章。

1、字段權(quán)限的設(shè)計(jì)

字段的權(quán)限控制,一般就是控制對應(yīng)角色人員的對某個表的一些敏感字段的可訪問性:包括可見、可編輯性等處理。
在設(shè)計(jì)字段權(quán)限的時候,我們需要了解這些還是基于RBAC的概念,基于角色進(jìn)行授權(quán)的,而且我們的字段列表是屬于具體的業(yè)務(wù)對象列表的,這里的業(yè)務(wù)對象是指一些我們具體的業(yè)務(wù)模塊,如客戶基礎(chǔ)信息、人員基礎(chǔ)信息、報價單等等,我們就是基于這些業(yè)務(wù)進(jìn)行字段的控制的。
如下界面所示,我們在權(quán)限系統(tǒng)里面也可以對其字段進(jìn)行權(quán)限控制,如下圖所示。先選擇左邊的具體角色,然后添加一些業(yè)務(wù)對象,并設(shè)置它們的權(quán)限即可。



首次業(yè)務(wù)對象需要用戶加入,這里以程序集中的實(shí)體類進(jìn)行字段信息的標(biāo)識處理,如下所示可以加載對應(yīng)業(yè)務(wù)信息。


我們在業(yè)務(wù)對象列表的【顯示設(shè)置】處可以單擊旁邊的按鈕,在彈出的界面上進(jìn)行條件的設(shè)置,如下界面效果所示。



這樣我們就完成了對某個業(yè)務(wù)對象的各個字段進(jìn)行配置了,具體的字段控制在業(yè)務(wù)模塊里面添加部分代碼即可實(shí)現(xiàn)了。
例如我們以系統(tǒng)黑名單為例介紹,通過上面的方式進(jìn)行設(shè)置,隱藏起始和結(jié)束IP地址的字段,那么列表界面得到的效果如下所示。



同時,如果系統(tǒng)界面有新增或者編輯界面,那么我們也需要隱藏才可以達(dá)到效果,如下是其的編輯界面效果(隱藏顯示那兩個字段了)。

以上就是整個字段權(quán)限控制的設(shè)計(jì)思路和實(shí)現(xiàn)了,但是具體我們是如何在業(yè)務(wù)模塊里面整合這些權(quán)限控制呢?下面我們進(jìn)行介紹。

2、字段權(quán)限的列表控制處理

前面我們介紹了在權(quán)限系統(tǒng)中進(jìn)行業(yè)務(wù)對象的字段權(quán)限的設(shè)置流程,以及以其中的【登陸系統(tǒng)黑白名單】的業(yè)務(wù)模塊進(jìn)行的演示,那么我們?nèi)绾尾拍茉谧约旱臉I(yè)務(wù)模塊里面進(jìn)行控制處理的呢?
首先我們需要在業(yè)務(wù)列表綁定的時候,需要獲取我們當(dāng)前用戶能夠訪問的字段列表,默認(rèn)是全部可見,但是如果用戶設(shè)置了條件,那么就需要獲取對應(yīng)的權(quán)限列表進(jìn)行控制了,具體的控制代碼如下所示。

//根據(jù)業(yè)務(wù)對象獲取對應(yīng)的顯示字段,如果沒有設(shè)置,那么根據(jù)FieldPermit表的配置獲取字段權(quán)限列表
var permitDict = BLLFactory<FieldPermit>.Instance.GetColumnsPermit(typeof(BlackIPInfo).FullName, Portal.gc.UserInfo.ID);
var displayColumns = BLLFactory<BlackIP>.Instance.GetDisplayColumns();
displayColumns = string.IsNullOrEmpty(displayColumns) ? string.Join(",", permitDict.Keys) : displayColumns;            
this.winGridViewPager1.DisplayColumns = displayColumns;

然后在設(shè)置字段的中文映射顯示

//設(shè)置字段的中文顯示
this.winGridViewPager1.ColumnNameAlias = BLLFactory<BlackIP>.Instance.GetColumnNameAlias();//字段列顯示名稱轉(zhuǎn)義

在對列表進(jìn)行數(shù)據(jù)綁定后,我們統(tǒng)一設(shè)置各個字段的權(quán)限的可讀寫、可見或隱藏值權(quán)限即可,如下代碼所示。

//獲取字段顯示權(quán)限,并設(shè)置
this.winGridViewPager1.gridView1.SetColumnsPermit(permitDict);

整個數(shù)據(jù)綁定的代碼如下所示,這些代碼可以利用代碼生成工具Database2Sharp進(jìn)行界面代碼統(tǒng)一生成

/// <summary>
/// 綁定列表數(shù)據(jù)
/// </summary>
private void BindData()
{
    //entity

    //根據(jù)業(yè)務(wù)對象獲取對應(yīng)的顯示字段,如果沒有設(shè)置,那么根據(jù)FieldPermit表的配置獲取字段權(quán)限列表
    var permitDict = BLLFactory<FieldPermit>.Instance.GetColumnsPermit(typeof(BlackIPInfo).FullName, Portal.gc.UserInfo.ID);
    var displayColumns = BLLFactory<BlackIP>.Instance.GetDisplayColumns();
    displayColumns = string.IsNullOrEmpty(displayColumns) ? string.Join(",", permitDict.Keys) : displayColumns;            
    this.winGridViewPager1.DisplayColumns = displayColumns;

    //設(shè)置字段的中文顯示
    this.winGridViewPager1.ColumnNameAlias = BLLFactory<BlackIP>.Instance.GetColumnNameAlias();//字段列顯示名稱轉(zhuǎn)義

    string where = GetConditionSql();
    List<BlackIPInfo> list = BLLFactory<BlackIP>.Instance.Find(where);
    this.winGridViewPager1.DataSource = new WHC.Pager.WinControl.SortableBindingList<BlackIPInfo>(list);
    this.winGridViewPager1.PrintTitle = "登陸系統(tǒng)的黑白名單列表報表";

    //獲取字段顯示權(quán)限,并設(shè)置
    this.winGridViewPager1.gridView1.SetColumnsPermit(permitDict);
}

對于DevExpress的GridControl列表控件,我們一般在處理過程中需要設(shè)置字段的DisplayText轉(zhuǎn)義,那么這種設(shè)置后,通過上面代碼處理的權(quán)限就會失效,我們可以利用對Tag的標(biāo)識的判斷進(jìn)行處理,如下所示,這樣就避免了權(quán)限控制無效的情況。

void gridView1_CustomColumnDisplayText(object sender, DevExpress.XtraGrid.Views.Base.CustomColumnDisplayTextEventArgs e)
{
    //如果字段權(quán)限不夠,那么字段的標(biāo)簽設(shè)置為*的
    if (string.Concat(e.Column.Tag) != "*")
    {
        if (e.Column.ColumnType == typeof(DateTime))
        {
            string columnName = e.Column.FieldName;
            if (e.Value != null)
            {
                if (Convert.ToDateTime(e.Value) <= Convert.ToDateTime("1900-1-1"))
                {
                    e.DisplayText = "";
                }
                else
                {
                    e.DisplayText = Convert.ToDateTime(e.Value).ToString("yyyy-MM-dd HH:mm");//yyyy-MM-dd
                }
            }
        }
        else if (e.Column.FieldName == "AuthorizeType")
        {
            if (e.Value != null)
            {
                e.DisplayText = ((AuthrizeType)e.Value).ToString();
            }
        }
    }
}

3、字段權(quán)限的顯示窗體控制處理

如果在開發(fā)Winform界面的時候,把列表的展示統(tǒng)一放在GridControl里面進(jìn)行展示,不再獨(dú)立設(shè)計(jì)展示窗體,那么上面列表控制就已經(jīng)達(dá)到了字段權(quán)限的控制目的了:可見或不可見、可編輯或只讀、顯示或隱藏值等處理。
在我的Winform框架中,我一般傾向于設(shè)計(jì)一個界面來展示業(yè)務(wù)對象的內(nèi)容,一般新增,查看或者編輯都放在這個窗體上展示信息,比較直觀,那么這種對字段權(quán)限的控制也需要延伸到這個顯示窗體上;
對于普通的編輯控件,我們只能控制控件的可讀寫、可見與否的處理。
首先我們設(shè)計(jì)一個函數(shù),用來設(shè)置控件的權(quán)限的,如下所示。

/// <summary>
/// 設(shè)置控件字段的權(quán)限顯示或者隱藏
/// </summary>
private void SetPermit()
{
    #region 設(shè)置控件和字段的對應(yīng)關(guān)系
    this.txtName.Tag = "Name";
    this.txtAuthorizeType.Tag = "AuthorizeType";
    this.txtForbid.Tag = "Forbid";
    this.txtIPStart.Tag = "IPStart";
    this.txtIPEnd.Tag = "IPEnd";
    this.txtNote.Tag = "Note";
    this.txtCreator.Tag = "Creator";
    this.txtCreateTime.Tag = "CreateTime";
    #endregion

    //獲取列表權(quán)限的列表
    var permitDict = CallerFactory<IFieldPermitService>.Instance.GetColumnsPermit(typeof(BlackIPInfo).FullName, Portal.gc.UserInfo.ID);
    this.SetControlPermit(permitDict, this.layoutControl1);
}

在上面,我們的邏輯就是先為每個控件綁定一個字段的標(biāo)識,最后通過獲取用戶的字段權(quán)限列表,對控件的權(quán)限進(jìn)行統(tǒng)一的控制處理即可。

為了開發(fā)的省時省力,這些代碼可以利用代碼生成工具Database2Sharp進(jìn)行界面代碼統(tǒng)一生成

完成上面SetPermit函數(shù)的處理,我們在窗體界面的顯示內(nèi)容上,最后統(tǒng)一設(shè)置控件的權(quán)限即可,如下代碼所示。

/// <summary>
/// 數(shù)據(jù)顯示的函數(shù)
/// </summary>
public override void DisplayData()
{
    InitDictItem();//數(shù)據(jù)字典加載(公用)

    if (!string.IsNullOrEmpty(ID))
    {
        #region 顯示信息
        BlackIPInfo info = CallerFactory<IBlackIPService>.Instance.FindByID(ID);
        if (info != null)
        {
            tempInfo = info;//重新給臨時對象賦值,使之指向存在的記錄對象

            txtName.Text = info.Name;
            txtAuthorizeType.SetComboBoxItem(info.AuthorizeType.ToString());
            txtForbid.Checked = info.Forbid;
            txtIPStart.Text = info.IPStart;
            txtIPEnd.Text = info.IPEnd;
            txtNote.Text = info.Note;
            txtCreator.Text = info.Creator;
            txtCreateTime.SetDateTime(info.CreateTime);
        }
        #endregion
        //this.btnOK.Enabled = Portal.gc.HasFunction("BlackIP/Edit");             
    }
    else
    {
        txtCreator.Text = Portal.gc.UserInfo.FullName;//默認(rèn)為當(dāng)前登錄用戶
        txtCreateTime.DateTime = DateTime.Now; //默認(rèn)當(dāng)前時間
        //this.btnOK.Enabled = Portal.gc.HasFunction("BlackIP/Add");  
    }

    RefreshUsers();

    SetPermit();
}


以上就是字段權(quán)限的設(shè)計(jì)思路,實(shí)現(xiàn)控制過程,這樣我們在權(quán)限里面實(shí)現(xiàn)了功能權(quán)限、菜單權(quán)限、數(shù)據(jù)記錄權(quán)限、字段權(quán)限的綜合控制,基本上能夠滿足大多數(shù)業(yè)務(wù)規(guī)則的要求了,從而提高了權(quán)限管理系統(tǒng)在整個應(yīng)用開發(fā)中的通用性、便利性,一致性。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容