設(shè)計案例之通用權(quán)限管理設(shè)計數(shù)據(jù)權(quán)限

本文將對這種設(shè)計思想作進一步的擴展,介紹數(shù)據(jù)權(quán)限的設(shè)計方案训枢。

權(quán)限控制可以理解托修,分為這幾種 :

【功能權(quán)限】:能做什么的問題,如增加產(chǎn)品恒界。

【數(shù)據(jù)權(quán)限】:能看到哪些數(shù)據(jù)的問題睦刃,如查看本人的所有訂單。

【字段權(quán)限】:能看到哪些信息的問題十酣,如供應(yīng)商賬戶涩拙,看不到角色、 部門等信息耸采。

   上面提到的那種設(shè)計就是【功能權(quán)限】兴泥,這種設(shè)計有一定的局限性,對于主體虾宇,只能明確地指定搓彻。對于不明確的,在這里可能就沒辦法處理嘱朽。比如下面這幾種情況:

數(shù)據(jù)僅當(dāng)前部門及上級可見

數(shù)據(jù)僅當(dāng)前用戶(本人)可見

類似這樣的就需要用到上面提的數(shù)據(jù)權(quán)限旭贬。

初步分析

【數(shù)據(jù)權(quán)限】是在【功能權(quán)限】的基礎(chǔ)上面進一步的擴展,比如可以查看訂單屬于【功能權(quán)限】的范圍搪泳,但是可以查看哪些訂單就是【數(shù)據(jù)權(quán)限】的工作了稀轨。

在設(shè)計中,我們規(guī)定好如果沒有設(shè)置了數(shù)據(jù)權(quán)限規(guī)則岸军,那么視為允許查看全部的數(shù)據(jù)奋刽。

幾個概念

【資源】:數(shù)據(jù)權(quán)限的控制對象,業(yè)務(wù)系統(tǒng)中的各種資源凛膏。比如訂單單據(jù)杨名、銷售單等。屬于提到的【領(lǐng)域】中的一種

主體】:用戶猖毫、部門台谍、角色等。

【條件規(guī)則】:用于檢索數(shù)據(jù)的條件定義

【數(shù)據(jù)規(guī)則】:用于【數(shù)據(jù)權(quán)限】的條件規(guī)則

應(yīng)用場景

**1吁断,訂單趁蕊,可以由本人查看 **

**2,銷售單仔役,可以由本人或上級領(lǐng)導(dǎo)查看 **

3掷伙,銷售單,銷售人員可以查看自己的又兵,銷售經(jīng)理只查看 銷售金額大于100,000的任柜。

我們能想到直接的方法卒废,在訪問數(shù)據(jù)的入口加入SQL Where條件來實現(xiàn),組織sql語句:

1宙地,whereUserID={CurrentUserID}

2摔认,whereUserID={CurrentUserID}or{CurrentUserID}in(領(lǐng)導(dǎo))

3,whereUserID={CurrentUserID}or({CurrentUserID} in(銷售經(jīng)理)and銷售金額>100000)

這些一個一個的"條件"宅粥,本文簡單理解為一個【數(shù)據(jù)規(guī)則】参袱,通常會與原來我們前臺的業(yè)務(wù)過濾條件合并再檢索出數(shù)據(jù)。

這是一種最直接的實現(xiàn)方式秽梅,在【資源】上面加一個【數(shù)據(jù)規(guī)則】(比如上面的三點)抹蚀。

這樣設(shè)計就是

【資源】 - 【數(shù)據(jù)規(guī)則】

   我又覺得不同的人應(yīng)該對應(yīng)不同的規(guī)則,那么也可以理解為企垦,一個用戶對應(yīng)不同的角色环壤,每一個角色有不一樣的【數(shù)據(jù)規(guī)則】,那么設(shè)計就變成【資源】 - 【主體】 - 【數(shù)據(jù)規(guī)則】竹观。

根據(jù)提供者的不同镐捧,準(zhǔn)備不同的權(quán)限應(yīng)對策略。

 這里可以簡單地介紹一下臭增,這個方案至少需要2張表懂酱,一個是  **【資源,主體誊抛,規(guī)則關(guān)系表】**列牺、一個是【數(shù)據(jù)規(guī)則表】

 關(guān)系表不能直接保存角色,因為你不確定什么時候業(yè)務(wù)需要按照【部門】或者【分公司】來定義數(shù)據(jù)規(guī)則

** 于是可以用Master拗窃、MasterKey 類似這樣的兩個字段來確定一個【主體】**

用XML方式的話是這樣配置的(放在數(shù)據(jù)庫也類似):

<?xml version="1.0" encoding="utf-8"?>

<settings>

** <rule view="訂單" role="銷售人員">**

** 銷售員 = {CurrentUserID}**

** </rule>**

** <rule view="訂單" role="總銷售經(jīng)理">**

** 銷售金額 > 100000**

** </rule>**

** <rule view="訂單" role="區(qū)域銷售經(jīng)理">**

** 銷售金額 > 100000 and 區(qū)域 = {當(dāng)前用戶所屬區(qū)域}**

** </rule>**

</settings>

   對于這種方式有興趣的朋友也可以試一下瞎领,兩種方式的【數(shù)據(jù)規(guī)則】是一樣的,但是本文沒有采用第二種設(shè)計方式随夸,因為它多了一層處理邏輯九默,我以為應(yīng)該設(shè)計越簡單越好,就采用第一種方式:

【資源】 - 【數(shù)據(jù)規(guī)則】

   當(dāng)然宾毒,上面是用SQL的方式來確定條件規(guī)則的驼修,我們當(dāng)然不會這么做。SQL雖然靈活诈铛,但是我們很難去維護乙各,也不知道SQL在我們的界面UI上面如何體現(xiàn)。難不成直接用一個文本框來顯示幢竹。這樣對應(yīng)一個開發(fā)人員來說不是問題耳峦,可是對應(yīng)系統(tǒng)管理員,很容易出問題焕毫。所以我們需要有另一方式來確定這一規(guī)則蹲坷,并最終可以轉(zhuǎn)換成我們的SQL語句驶乾。

      我們的設(shè)計關(guān)鍵在于如何規(guī)范好這些【數(shù)據(jù)規(guī)則】,這個規(guī)則必須是對前端友好的冠句,而且是對后臺友好的轻掩,JSON顯然是很好的方式。

規(guī)則說明:

1懦底,數(shù)據(jù)權(quán)限規(guī)則總是:{屬性 條件 允許值}

2,數(shù)據(jù)權(quán)限規(guī)則可以合并罕扎。比如 ( {當(dāng)前用戶 屬于 銷售人員} and {訂單銷售員 等于 當(dāng)前用戶} ) Or {當(dāng)前用戶 屬于 銷售經(jīng)理}

3聚唐,最終我們會用JSON格式

   在檢索數(shù)據(jù)時會先判斷有沒有注冊了某某【資源】的【條件規(guī)則】,如果有腔召,那么加載這個【條件規(guī)則】并合并到我們前臺的【搜索條件】(你的業(yè)務(wù)界面應(yīng)該有一個搜索框吧)

   如下圖定義了客戶信息的搜索框杆查,我們搜索客戶ID包括AN,我們組織成的規(guī)則將會是:

{"rules":[{"field":"CustomerID","op":"like","value":"AN","type":"string"}],"op":"and"}

image

為了更好地理解【數(shù)據(jù)規(guī)則】臀蛛,這里介紹一下【通用查詢機制】

【通用查詢機制】

   權(quán)限控制總離不開一些條件的限制(比如查看當(dāng)前部門的單據(jù))亲桦,如果沒有完善的通用查詢規(guī)則機制,那么在做權(quán)限條件過濾的時候你會覺得很別扭浊仆。這里介紹一個通用查詢方案客峭,然后再介紹如何實現(xiàn)【數(shù)據(jù)規(guī)則】。

早些時候我寫過一篇關(guān)于ligerGrid結(jié)合.net設(shè)計通用處理類的文章《 jQuery liger ui ligerGrid 打造通用的分頁排序查詢表格(提供下載) 》抡柿。里面提到的過濾信息是直接的SQL語句舔琅。這是不可靠,而且不安全的洲劣。

在前端傳輸給后臺的過濾信息不應(yīng)該是直接的SQL备蚓,而應(yīng)該是一組過濾規(guī)則。在ligerui V1.1.8 已經(jīng)加入了一個條件過濾器插件囱稽,這個插件組成的規(guī)則數(shù)據(jù)才是我受推薦的:

比如如下

{"rules":[{"field":"OrderDate","op":"less","value":"2012-01-01"},{"field":"CustomerID","op":"equal","value":"VINET"}],"op":"and"}

規(guī)則描述:

  查找顧客VINET所有訂單時間小于2011-01-01的單據(jù)

  這樣的數(shù)據(jù)是安全的郊尝,而且是通用的(你甚至可以再加一個OR子查詢)。無論是在前端還是后臺战惊,無論你使用什么樣的組件流昏,都可以很好地利用。

通用后臺的翻譯样傍,就可以生成這樣SQL的參數(shù):

Text:

( [OrderDate]< @p1 and [CustomerID]=@p2)

Parameters:

p1:2012-01-01

p2:VINET

下面來點復(fù)雜的:查找 顧客VINET或者TOMSP横缔,所有訂單時間小于2011-01-01的單據(jù)

{

"rules":[{"field":"OrderDate","op":"less","value":"2012-01-01"}],

"groups":[

** {"rules":[{"field":"CustomerID","op":"equal","value":"VINET"}, **

** {"field":"CustomerID","op":"equal","value":"TOMSP"}],"op":"or"}**

],

"op":"and"

}

Text:([OrderDate]<@p1and([CustomerID]=@p2or[CustomerID]=@p3))

Parameters:

p1:2012-01-01

p2:VINET

p3:TOMSP

這個過濾規(guī)則分為三個部分:【分組】、【規(guī)則】(字段衫哥、值茎刚、操作符)、【操作符】(and or)撤逢,而自身就是一個分組膛锭。

這種簡單的結(jié)構(gòu)就可以滿足全部的情況粮坞。

當(dāng)然,上面提到的這些條件都是在前臺定義(可能是用戶在搜索框自己輸入的)的初狰,而在后臺莫杈,我們可能會定義一下【隱藏條件】,比如說 【員工只能查看自己的】奢入,要怎么做呢筝闹,其實很簡單,只需要在后臺接收到這個過濾條件(前臺toJSON,后臺解析JSON)以后,再加上一個過濾規(guī)則(隱藏條件):

{field:'EmployeeID',op:'equal',value:5}

可以將原來的過濾規(guī)則當(dāng)做一個分組加入進行:

{op:'and',groups:[

{"rules":[{"field":"OrderDate","op":"less","value":"2012-01-01"}],

"groups":[

{"rules":[

{"field":"CustomerID","op":"equal","value":"VINET"},{"field":"CustomerID","op":"equal","value":"TOMSP"}],"op":"or"}

],"op":"and"}

],rules:

[{field:'EmployeeID',op:'equal',value:5}]

}

Text:

([EmployeeID]=@p1 and ([OrderDate]< @p2 and([CustomerID]=@p3 or [CustomerID]=@p4)))

Parameters:

p1:5

p2:2012-01-01

p3:VINET

p4:TOMSP

   這樣的【條件規(guī)則】才是我們想要的洽腺,不僅在前端可以很好地解析,也可以在后臺進行處理议双。在后臺我們會定義跟這種數(shù)據(jù)結(jié)構(gòu)對應(yīng)的類,那么再定義一個翻譯成SQL的類:
image

數(shù)據(jù)權(quán)限規(guī)則

說了這些捉片,可以開始介紹如何實現(xiàn)【數(shù)據(jù)規(guī)則】了:

上面提到的【隱藏條件】平痰,就是我介紹的【數(shù)據(jù)規(guī)則】

試想一些,這樣 前臺的過濾規(guī)則伍纫,再加上我們之間定義好的 【數(shù)據(jù)權(quán)限】控制 過濾條件宗雇。不就達(dá)到目的了嗎。

先看看我們在數(shù)據(jù)庫里保存的這些【數(shù)據(jù)規(guī)則】:

image

看不明白翻斟?那來個清楚一點的:

image

規(guī)則描述

訂單:【訂單管理員和演示角色可以查看所有的】逾礁,【訂單查看員】只能查看自己的

產(chǎn)品:【基礎(chǔ)信息錄入員和演示角色可以查看所有的】,【供應(yīng)商】只能查看自己的

{CurrentEmployeeID}表示當(dāng)前的員工访惜。

實質(zhì)上嘹履,我們還可以根據(jù)當(dāng)前用戶信息定義需要的參數(shù),比如:

{CurrentUserID} 當(dāng)前用戶Id 债热,對應(yīng)表【CF_User】

{CurrentRoleID} 當(dāng)前角色I(xiàn)d 砾嫉,對應(yīng)表 【CF_Role】

{CurrentDeptID} 當(dāng)前用戶部門Id,對應(yīng)表【CF_Department】

{CurrentEmployeeID} 當(dāng)前用戶員工Id窒篱,對應(yīng)表【Employees】(CF_User.EmployeeID)

{CurrentSupplierID} 當(dāng)前用戶供應(yīng)商Id焕刮,對應(yīng)表【Suppliers】(CF_User.SupplierID)

在數(shù)據(jù)庫中我們直接保存這些用戶參數(shù),在“翻譯”規(guī)則成為SQL時墙杯,會替換掉:

image

比如查看訂單配并,我們得到的SQL,可能是這樣的:

Text:

SELECTFROM(SELECTTOP20FROM(SELECTTOP40*FROM[Orders]WHERE(1=1and((@p1in(@p2,@p3))or(@p4=@p5and[EmployeeID]=@p6)))ORDERBYOrderIDASC)AStmptableinnerORDERBYOrderIDDESC)AStmptableouterORDERBYOrderIDASC

Parameters:

@p1[Int32]=7

@p2[Int32]=2

@p3[Int32]=6

@p4[Int32]=7

@p5[Int32]=7

@p6[Int32]=1

{CurrentRuleID} 替換為 7

{CurrentEmployeeID} 替換為1

下圖是我們設(shè)計【數(shù)據(jù)權(quán)限】的界面高镐,可以選擇所有的字段溉旋,包括幾個用戶信息:

image

這些字段不僅僅只是在文本框中輸入值,那么可以自定義數(shù)據(jù)來源:

varfieldEditors={};

fieldEditors['Orders']={

'ShipCity': { type:'combobox',

options: {

width:200,

url: "../handler/select.ashx?view=Orders&idfield=ShipCity&textfield=ShipCity&distinct=true"

}

}

};

效果界面:

image

實際應(yīng)用

既然是數(shù)據(jù)權(quán)限控制嫉髓,如果有一個統(tǒng)一的數(shù)據(jù)接收入口观腊,我們倒是可以利用這個入口做一些工作邑闲。

比如【ligerRM權(quán)限管理系統(tǒng)】統(tǒng)一使用 grid.ashx 這個數(shù)據(jù)處理程序作為列表數(shù)據(jù)的接收入口。

有了統(tǒng)一的接口梧油,方便做權(quán)限的控制苫耸,使用過 ligerGrid Javascript表格,或者類似插件的朋友儡陨,應(yīng)該比較清楚服務(wù)器的交互原理褪子。

在grid.ashx中,我們會通過

【視圖/表名 】迄委、 【排序信息】褐筛、【分頁信息】、【過濾信息】

這幾個指標(biāo)來獲取指定的數(shù)據(jù)叙身。

而在實際的業(yè)務(wù)中,可能會引入權(quán)限的控制硫狞。比如某某【資源】信轿,只能由當(dāng)前用戶自身才能查看,或者只能由當(dāng)前用戶部門及上級部門才能查看残吩。對于這些控制财忽,我們采用對這些可能做權(quán)限控制的【資源】注冊一組【條件規(guī)則】的方式來進行。

image

我們將找到view定義好的【數(shù)據(jù)權(quán)限規(guī)則】泣侮,然后和用戶在前臺搜索框輸入的【搜索規(guī)則】合并:

上面的代碼就是數(shù)據(jù)條件合并的例子即彪,這樣便得到了我們最終需要的 過濾規(guī)則。

結(jié)語

本文提出了數(shù)據(jù)權(quán)限的一種實現(xiàn)思路活尊,只是本人在做一個web應(yīng)用時構(gòu)思的方案隶校,談不上規(guī)范,歡迎提出你的建議意見蛹锰。

可以在http://case.ligerui.com體驗實際的應(yīng)用效果深胳。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市铜犬,隨后出現(xiàn)的幾起案子舞终,更是在濱河造成了極大的恐慌,老刑警劉巖癣猾,帶你破解...
    沈念sama閱讀 212,718評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件敛劝,死亡現(xiàn)場離奇詭異,居然都是意外死亡纷宇,警方通過查閱死者的電腦和手機夸盟,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,683評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來呐粘,“玉大人满俗,你說我怎么就攤上這事转捕。” “怎么了唆垃?”我有些...
    開封第一講書人閱讀 158,207評論 0 348
  • 文/不壞的土叔 我叫張陵五芝,是天一觀的道長。 經(jīng)常有香客問我辕万,道長枢步,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,755評論 1 284
  • 正文 為了忘掉前任渐尿,我火速辦了婚禮醉途,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘砖茸。我一直安慰自己隘擎,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,862評論 6 386
  • 文/花漫 我一把揭開白布凉夯。 她就那樣靜靜地躺著货葬,像睡著了一般。 火紅的嫁衣襯著肌膚如雪劲够。 梳的紋絲不亂的頭發(fā)上震桶,一...
    開封第一講書人閱讀 50,050評論 1 291
  • 那天,我揣著相機與錄音征绎,去河邊找鬼。 笑死人柿,一個胖子當(dāng)著我的面吹牛柴墩,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播顷扩,決...
    沈念sama閱讀 39,136評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼拐邪,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了隘截?” 一聲冷哼從身側(cè)響起扎阶,我...
    開封第一講書人閱讀 37,882評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎婶芭,沒想到半個月后东臀,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,330評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡犀农,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,651評論 2 327
  • 正文 我和宋清朗相戀三年惰赋,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,789評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡赁濒,死狀恐怖轨奄,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情拒炎,我是刑警寧澤挪拟,帶...
    沈念sama閱讀 34,477評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站击你,受9級特大地震影響玉组,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜丁侄,卻給世界環(huán)境...
    茶點故事閱讀 40,135評論 3 317
  • 文/蒙蒙 一惯雳、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧鸿摇,春花似錦石景、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,864評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至庐镐,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間变逃,已是汗流浹背必逆。 一陣腳步聲響...
    開封第一講書人閱讀 32,099評論 1 267
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留揽乱,地道東北人名眉。 一個月前我還...
    沈念sama閱讀 46,598評論 2 362
  • 正文 我出身青樓,卻偏偏與公主長得像凰棉,于是被迫代替她去往敵國和親损拢。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,697評論 2 351

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