|
權(quán)限系統(tǒng)(1)--基本模式
在系統(tǒng)中發(fā)生的事情,抽象的說(shuō)都是某個(gè)主體(subject)在某個(gè)資源(resource)上執(zhí)行了某個(gè)操作(operation)。 subject
--[operation]--> resource 所謂權(quán)限管理,就是在這條信息傳遞路徑中加上一些限制性控制。 主體試圖去做的
limited by 系統(tǒng)允許主體去做的 =
主體實(shí)際做的。 可以看到,權(quán)限控制基本對(duì)應(yīng)于filter模式。subject試圖去做的事情應(yīng)該由業(yè)務(wù)邏輯決定,因而應(yīng)該編碼在業(yè)務(wù)系統(tǒng)中。
先考慮最粗粒度的控制策略,控制點(diǎn)加在subject處,即無(wú)論從事何種操作,針對(duì)何種資源,我們首先需要確認(rèn)subject是受控的。只有通過(guò)認(rèn)證的用戶才能使用系統(tǒng)功能,這就是authentication。boolean
isAllowed
subject) 稍微復(fù)雜一些,控制可以施加在subject和operation的邊界處(此時(shí)并不知道具體進(jìn)行何種操作),稱(chēng)為模塊訪問(wèn)控制,即只有某些用戶才能訪問(wèn)特定模塊。isAllowed(subject,
operation
set) 第三級(jí)控制直接施加在operation上,即操作訪問(wèn)控制。operation知道resource和subject(但它尚沒(méi)有關(guān)于resource的細(xì)節(jié)知識(shí)),我們能夠采取的權(quán)限機(jī)制是bool
isAllowed(subject, operation, resource),
返回true允許操作,返回false則不允許操作。
最簡(jiǎn)單的情況下,subject與resource之間的訪問(wèn)控制關(guān)系是靜態(tài)的,可以直接寫(xiě)成一個(gè)權(quán)限控制矩陣
for
operationA: resourceA resourceB subjectA 1 0 subjectB 0
1
isAllowed(subjectA,
resourceA)恒等于true
如果多個(gè)operation的權(quán)限控制都可以通過(guò)這種方式來(lái)表示,則多個(gè)權(quán)限控制矩陣可以疊加在一起
for
operationA, operationB: resourceA resourceB subjectA 10 01 subjectB 01
11
當(dāng)subject和resource的種類(lèi)很多時(shí),權(quán)限控制矩陣急劇膨脹,它的條目數(shù)是N*M。很顯然,我們需要進(jìn)行矩陣分解。這也是最基本的控制手段之一:
在系統(tǒng)中增加一個(gè)瓶頸,或者說(shuō)尋找到隱含的結(jié)構(gòu)。 subject_resource = subject_role *
role_resource 這樣系統(tǒng)權(quán)限配置條目的數(shù)量為 N*R + R*M,
如果R的數(shù)目遠(yuǎn)小于subject和resource,則實(shí)現(xiàn)簡(jiǎn)化。這稱(chēng)為RBAC(role based access
control),它的一個(gè)額外好處是權(quán)限系統(tǒng)的部分描述可以獨(dú)立于subject存在,即在系統(tǒng)中沒(méi)有任何用戶的時(shí)候,通過(guò)角色仍然可以表達(dá)部分權(quán)限信息??梢哉f(shuō)角色是subject在權(quán)限系統(tǒng)中的代理(分解)。
有時(shí)候引入一個(gè)瓶頸還不過(guò)癮,有人引入組的概念,與role串聯(lián), subject_resource
= subject_group_role * role_resource 或著group與role并聯(lián), subject_resource =
subject_group *
group_resource
與role稍有不同,一般情況下group的業(yè)務(wù)含義更加明顯,可能對(duì)應(yīng)于組織結(jié)構(gòu)等。將組織機(jī)構(gòu)明確引入權(quán)限體系,有的時(shí)候比較方便,但對(duì)于權(quán)限系統(tǒng)自身的穩(wěn)定性而言,未見(jiàn)得有什么太大的好處。并聯(lián)模式有些多余,串聯(lián)模式又過(guò)于復(fù)雜,細(xì)節(jié)調(diào)整困難,特別是多條控制路徑造成的沖突情況。一般情況下,我不提倡將group引入權(quán)限控制中。
比操作控制更加深入的控制就是數(shù)據(jù)控制了,此時(shí)需要對(duì)于resource的比較全面的知識(shí)。雖然表面上,仍然是 boolean
isAllowed(subject, operation,
resource),但控制函數(shù)需要知道resource的細(xì)節(jié)。例如行級(jí)控制(row-level)或者列級(jí)控制(column-level)的實(shí)現(xiàn)。因?yàn)槲覀円话闱闆r下不可能將每一個(gè)條目都建模為獨(dú)立的resource,而只能是存在一個(gè)整體描述,例如所有密級(jí)為絕密的文檔。在witrix平臺(tái)中,數(shù)據(jù)控制主要通過(guò)數(shù)據(jù)源的filter來(lái)實(shí)現(xiàn),因?yàn)椴樵儣l件(數(shù)據(jù)的定位條件)已經(jīng)被對(duì)象化為Query類(lèi),所以我們可以在合適的地方自由的追加權(quán)限控制條件。
以上的討論中,權(quán)限控制都是根據(jù)某些靜態(tài)描述信息來(lái)進(jìn)行的,但現(xiàn)實(shí)世界是多變的。最簡(jiǎn)單的,當(dāng)subject從事不同業(yè)務(wù)時(shí),對(duì)應(yīng)于同一組資源,也可能對(duì)應(yīng)的權(quán)限控制并不同(在witrix平臺(tái)中,對(duì)應(yīng)于IDataSource的模式切換)。更復(fù)雜一些,
在不同的時(shí)刻, 我們需要根據(jù)其他附加信息來(lái)作出是否允許操作的判斷, 即此時(shí)我們權(quán)限設(shè)置的不僅僅是一些靜態(tài)的描述信息, 而是一個(gè)完整的控制函數(shù),
這就是所謂的工作流權(quán)限控制,一種動(dòng)態(tài)權(quán)限控制.
權(quán)限系統(tǒng)(2)--operation
權(quán)限控制可以看作一個(gè)filter模式的應(yīng)用, 這也符合AOP思想的應(yīng)用條件。在一個(gè)簡(jiǎn)化的圖象中,我們只需要將一個(gè)判別函數(shù)
isAllowed(subject, operation,
resource)插入到所有安全敏感的函數(shù)調(diào)用之前就可以了。雖然概念上很完美,具體實(shí)現(xiàn)的時(shí)候仍然有一些細(xì)節(jié)上的問(wèn)題?;镜睦щy在于很難在最細(xì)的粒度上指定權(quán)限控制規(guī)則(連續(xù)的?動(dòng)態(tài)的?可擴(kuò)展的?),因而我們只能在一些關(guān)鍵處指定權(quán)限規(guī)則,或者設(shè)置一些整體性的權(quán)限策略,然后通過(guò)特定的推理來(lái)推導(dǎo)出細(xì)粒度的權(quán)限規(guī)則,這就引出結(jié)構(gòu)的問(wèn)題。我們需要能夠?qū)?quán)限控制策略進(jìn)行有效的描述(控制策略的結(jié)構(gòu)),并且決定如何與程序結(jié)構(gòu)相結(jié)合。subject,
operation和resource為了支持推理,都可能需要分化出復(fù)雜的結(jié)構(gòu),而不再是簡(jiǎn)單的原子性的概念。而在與程序結(jié)構(gòu)結(jié)合這一方面,雖然AOP使得我們可以擴(kuò)展任何函數(shù),但這種擴(kuò)展需要依賴于cutpoint處所能得到的信息,因而權(quán)限控制的有效實(shí)施也非常依賴于功能函數(shù)本身良好的設(shè)計(jì)。有的時(shí)候因?yàn)樾枰獙?duì)結(jié)構(gòu)有過(guò)于明確的假定,權(quán)限控制的實(shí)現(xiàn)不得不犧牲一定的通用性。
下面我們將分別討論一下operation,
subject和resource的結(jié)構(gòu)分解的問(wèn)題。首先是operation。 說(shuō)到推理結(jié)構(gòu),讓人最先想起的就是決策樹(shù),樹(shù)形結(jié)構(gòu),在面向?qū)ο笳Z(yǔ)言中可以對(duì)應(yīng)于繼承。金字塔式的樹(shù)形結(jié)構(gòu)也正是在現(xiàn)實(shí)世界中我們應(yīng)用最多的控制結(jié)構(gòu)。通過(guò)層層分解,operation的結(jié)構(gòu)可以組織為一棵樹(shù), 應(yīng)用程序
==> 各個(gè)子系統(tǒng) ==> 每個(gè)子系統(tǒng)的功能模塊 ==> 子功能模塊 ==> 每個(gè)模塊的功能點(diǎn)(具有明確的業(yè)務(wù)含義)
==>
每個(gè)功能點(diǎn)對(duì)應(yīng)的訪問(wèn)函數(shù)(程序?qū)崿F(xiàn)中的結(jié)構(gòu)) 一個(gè)常見(jiàn)的需求是根據(jù)權(quán)限配置決定系統(tǒng)菜單樹(shù)的顯示,一般控制用戶只能看到自己有權(quán)操作的功能模塊和功能按鈕。這種需求的解決方法是非常直接的。首先,在后臺(tái)建立子系統(tǒng)到功能模塊,功能模塊到功能點(diǎn)以及功能點(diǎn)到實(shí)現(xiàn)函數(shù)之間的映射表(如果程序組織具有嚴(yán)格規(guī)范,這甚至可以通過(guò)自動(dòng)搜集得到)。然后,在權(quán)限配置時(shí)建立用戶與功能點(diǎn)之間的關(guān)聯(lián)。此時(shí),通過(guò)一個(gè)視圖,我們就可以搜集到用戶對(duì)哪些功能模塊具有訪問(wèn)權(quán)限的信息。
為了控制菜單樹(shù)的顯示,witrix平臺(tái)中的SiteMap采用如下策略: 1.
如果用戶對(duì)某個(gè)子功能具有操作權(quán)限,則所有父菜單項(xiàng)都缺省可用 2.
如果用戶對(duì)某個(gè)功能具有操作權(quán)限,并且標(biāo)記為cascade,則所有子菜單項(xiàng)都自動(dòng)缺省可用 3.
如果明確指定功能不可用,則該菜單及子菜單都強(qiáng)制不可用 4. 如果明確指定功能對(duì)所有人可用,則不驗(yàn)證權(quán)限,所有子菜單自動(dòng)缺省可用 4.
強(qiáng)制設(shè)定覆蓋缺省值 5. 不可用的菜單缺省不可見(jiàn) 6. 明確標(biāo)記為可見(jiàn)的菜單即使不可用也可見(jiàn) 7.
父菜單可見(jiàn)子菜單才可見(jiàn) 我們通過(guò)預(yù)計(jì)算來(lái)綜合考慮這些相互影響的控制策略。盡量將推導(dǎo)運(yùn)算預(yù)先完成也是解決性能問(wèn)題的不二法門(mén)。
在witrix平臺(tái)中,每一次網(wǎng)絡(luò)訪問(wèn)的url都符合jsplet框架所要求的對(duì)象調(diào)用格式,需要指定objectName和objectEvent參數(shù),這就對(duì)應(yīng)于功能點(diǎn)的訪問(wèn)函數(shù)。訪問(wèn)控制點(diǎn)集中在objectManager并且訪問(wèn)格式是標(biāo)準(zhǔn)的。使用spring等AOP方式實(shí)現(xiàn)細(xì)粒度訪問(wèn)控制,困難似乎在于不容易引入外部配置信息(例如功能點(diǎn)信息等),而且控制點(diǎn)所對(duì)應(yīng)的對(duì)象函數(shù)格式也不統(tǒng)一,因而多數(shù)需要在細(xì)粒度上一一指定。
權(quán)限系統(tǒng)(3)-- subject
權(quán)限控制中,subject可能不會(huì)簡(jiǎn)單的對(duì)應(yīng)于userId, 而是包含一系列的security
token或certificate,
例如用戶登陸地址,登陸時(shí)間等。一般情況下,這些信息在權(quán)限系統(tǒng)中的使用都是很直接的,不會(huì)造成什么問(wèn)題。 subject域中最重要的結(jié)構(gòu)是user和role的分離,可以在不存在user的情況下,為role指定權(quán)限。有人進(jìn)一步定義了userGroup的概念,可以為userGroup指定role,而user從其所屬的group繼承role的設(shè)置。一般情況下,我不提倡在權(quán)限系統(tǒng)中引入userGroup的概念。這其中最重要的原因就是它會(huì)造成多條權(quán)限信息傳遞途徑,從而產(chǎn)生一種路徑依賴,
并可能出現(xiàn)信息沖突的情況。一般user與group的關(guān)聯(lián)具有明確的業(yè)務(wù)含義,因而不能隨意取消。如果我們希望對(duì)user擁有的權(quán)限進(jìn)行細(xì)調(diào),除去user從group繼承的某個(gè)不應(yīng)該擁有的權(quán)限,解決的方法很有可能是所謂的負(fù)權(quán)限,即某個(gè)權(quán)限條目描述的是不能做某某事。負(fù)權(quán)限會(huì)造成各個(gè)權(quán)限設(shè)置之間的互相影響,造成必須嘗試所有權(quán)限規(guī)則才能作出判斷的困境,引出對(duì)額外的消歧策略的需求,這些都極大的限制了系統(tǒng)的可擴(kuò)展性。在允許負(fù)權(quán)限的環(huán)境中,管理員將無(wú)法直接斷定某個(gè)權(quán)限設(shè)置的最終影響,他必須在頭腦中完成所有的權(quán)限運(yùn)算之后才能理解某用戶最終擁有的實(shí)際權(quán)限,如果發(fā)現(xiàn)權(quán)限設(shè)置沖突,管理員可能需要多次嘗試才能找到合適方案。這種配置時(shí)的推理需求可能會(huì)增加配置管理的難度,造成微妙的安全漏洞,而且負(fù)權(quán)限導(dǎo)致的全局關(guān)聯(lián)也降低了權(quán)限系統(tǒng)的穩(wěn)定性。我更傾向于將group作為權(quán)限設(shè)置時(shí)的一種輔助標(biāo)記手段,系統(tǒng)中只記錄用戶最終擁有的角色,即相當(dāng)于記錄用戶通過(guò)group擁有權(quán)限的推導(dǎo)完成的結(jié)果,
如果需要權(quán)限細(xì)調(diào),我們直接在用戶擁有的角色列表上直接進(jìn)行。當(dāng)然,如果實(shí)現(xiàn)的復(fù)雜一些,權(quán)限系統(tǒng)對(duì)外暴露的接口仍然可以模擬為能夠指定userGroup的權(quán)限。 推理在面向?qū)ο笳Z(yǔ)言中最明顯的表現(xiàn)是繼承,所以有些人將subject域中的推理直接等價(jià)于role之間的繼承問(wèn)題,這未必是最好的選擇。繼承可以形成非常復(fù)雜的推理關(guān)系,但是可能過(guò)于復(fù)雜了(特別是直接使用sql語(yǔ)句無(wú)法實(shí)現(xiàn)樹(shù)形推理查詢)。按照級(jí)列理論,從不相關(guān)發(fā)展到下一階段是出現(xiàn)簡(jiǎn)單的序關(guān)系,即我們可以說(shuō)subject出現(xiàn)級(jí)別上的差異,高級(jí)別subject將自動(dòng)具有低級(jí)別的權(quán)限。一種選擇是定義roleRank,規(guī)定高級(jí)別role自動(dòng)具有低級(jí)別role的權(quán)限,但考慮到user與role的兩分結(jié)構(gòu),我們也可以同時(shí)定義userRank和roleRank,規(guī)定高級(jí)別user自動(dòng)具有低級(jí)別的role,而role之間不具有推理關(guān)系。在面向?qū)ο箢I(lǐng)域中,我們已經(jīng)證實(shí)了完全采用繼承來(lái)組織對(duì)象關(guān)系會(huì)導(dǎo)致系統(tǒng)的不穩(wěn)定,所以我傾向于第二種選擇,即將role看作某種類(lèi)似于interface的東西,一種權(quán)限的切片。為了進(jìn)一步限制這種推導(dǎo)關(guān)系,我們可以定義所謂的安全域的概念.
security domain, 規(guī)定推導(dǎo)只能在一定的域中才能進(jìn)行。 select user.userId, role.roleId from
user, role where user.userRank > role.roleRank and user.domain =
role.domain
將權(quán)限控制一般需要施加在最細(xì)的粒度上,這在復(fù)雜的系統(tǒng)中可能過(guò)于理想化了。復(fù)雜的情況下我們需要進(jìn)行局部化設(shè)計(jì),即進(jìn)行某些敏感操作之前進(jìn)行一系列復(fù)雜的權(quán)限校驗(yàn)工作。當(dāng)完成這些工作之后,進(jìn)入某個(gè)security
zone,
在其中進(jìn)行操作就不再需要校驗(yàn)了。 總的來(lái)說(shuō),權(quán)限系統(tǒng)采用非常復(fù)雜的結(jié)構(gòu)效果未必理想。很多時(shí)候只是個(gè)管理模式的問(wèn)題,應(yīng)該盡量通過(guò)重新設(shè)計(jì)權(quán)限空間的結(jié)構(gòu)來(lái)加以規(guī)避。不過(guò)在一些非常復(fù)雜的權(quán)限控制環(huán)境下,也許簡(jiǎn)單的描述信息確實(shí)很難有效的表達(dá)權(quán)限策略(雖然我從未遇到過(guò)),此時(shí)嘗試一下規(guī)則引擎可能比在權(quán)限系統(tǒng)中強(qiáng)行塞入越來(lái)越多的約束要好的多
權(quán)限系統(tǒng)(4)--resource
權(quán)限管理中進(jìn)行數(shù)據(jù)訪問(wèn)控制,其基本模式如下 operation target = selector(resource)
selector = user selector + auth
filter 這里需要對(duì)resource的結(jié)構(gòu),以及選擇算子的顯式建模。selector必須允許權(quán)限系統(tǒng)追加filter,例如 IDataSource包中所使用的Query對(duì)象。 sql語(yǔ)言的表達(dá)能力有限,
作為選擇算子來(lái)使用有時(shí)需要resource作一些結(jié)構(gòu)上的調(diào)整,增加一些冗余的字段。例如表達(dá)一段時(shí)間內(nèi)的利率,我們需要使用from_date和to_date兩個(gè)字段來(lái)進(jìn)行描述,其中to_date的值與下一條記錄的from_date相同。 value
from_date to_date 0.01 2003-01-01 2003-05-01 0.012 2003-05-01 2004-01-01
如果表達(dá)一條航線中的多個(gè)階段,我們可能會(huì)在每條記錄中增加起始站和終點(diǎn)站兩個(gè)字段。 更重要的一個(gè)常見(jiàn)需求是樹(shù)形結(jié)構(gòu)在關(guān)系數(shù)據(jù)庫(kù)中的表達(dá)。為了能夠直接操縱一個(gè)分支下的所有記錄,在層次固定的情況下,我們可能會(huì)增加多個(gè)分類(lèi)字段,例如數(shù)據(jù)倉(cāng)庫(kù)中的層次維度。在層次數(shù)目不確定的情況下,我們將不得不使用層次碼或者類(lèi)似于url的其他方案,通過(guò)layer_code
like ‘01.01.%‘
之類(lèi)的語(yǔ)句實(shí)現(xiàn)分支選擇。為了限制選擇的深度,我們可能還需要layer_level字段?;趯哟未a和層次數(shù),我們可以建立多種選擇算子,例如包含所有直接子節(jié)點(diǎn),包含自身及所有父節(jié)點(diǎn)等等。 http://www./oracle/or-articles/tropashko4
權(quán)限系統(tǒng)(5)--動(dòng)態(tài)性
動(dòng)態(tài)權(quán)限最簡(jiǎn)單的一個(gè)表現(xiàn)是時(shí)限性,subject只在某個(gè)時(shí)間段內(nèi)具有某種權(quán)限。這只需要在user和role的映射中,或者role自身的屬性中增加startTime和expireTime即可。
更復(fù)雜的動(dòng)態(tài)性一般與流程控制相關(guān),此時(shí)權(quán)限控制應(yīng)該由工作流系統(tǒng)完成,而不是在數(shù)據(jù)上增加越來(lái)越多的權(quán)限標(biāo)記。在witrix平臺(tái)中,使用tpl模板技術(shù)來(lái)定制權(quán)限設(shè)置。
|