|
前言
如何實現一個高效簡單的系統權限體系是我們長期以來都在思考的問題,也是最近一年來我思考得最多的問題,我們所期望的權限都是應當能夠根據應用的需要不斷添加和擴展的權限,并且最好能夠以最簡單的方式來支持,那就最好不過了。
內容
- 什么是權限系統
- 一個簡單的設計
- 基于角色的訪問
- 最初的數據權限
- 更好的解決方法
- 最近的戰役
- 總結
什么是權限系統
那么我們需要一個什么樣的權限系統呢或者說什么是權限,我查看了很多的相關資料想要試圖解決這個問題,最后看一個最簡單最明確的答案"安全問題就是解決誰對什么能夠進行什么控制的問題”。如何來分析這段話呢,我敢保證這是我見過的最明確也是最抽象的需求,通過什么樣的方式來分析和解決這個需求問題呢。
而對復雜的問題我們必須拿出強大武器才行啊,對于不明確的概念我們首先需要完成的是將“概念明確化”先將這段話中不明確的代詞進行明確化,那么我們就從第一個代詞開始“誰”是指什么呢,“員工”,“用戶”,“領導”,...,還是什么其它呢,我想對于不同的問題我想需要采用不同的概念,如果這個系統只是用于解決公司內容的相關問題,那么這里使用“員工”最好不過,如果專門用于解決“領導”的個人問題,那么“領導”也不錯。這里主要需要考慮我們所面臨問題和抽象的層次,同時還需考慮到具體應用的行業標準。對于需要大多數情況采用“用戶”或“當前用戶”是一個比較好抽象,我們這里采用“當前用戶”,這樣比“用戶”更明確一些,那么這段需求就變成了“安全問題就是解決當前用戶對什么能夠進行什么控制的問題”。
好解決了第一個抽象之后,對于其它問題我們同樣采用相關的方式來進行分析,“當前用戶對什么” 之中的“什么”當前相關問題的抽象層次之中基本上都是采用“安全資源對象”來進行抽象的,當然也可以根據實際處理的問題進行抽象,我們這里主要是考慮通用性。而對于“能夠進行什么訪問”之中的“什么”這里也需要根據相關問題的來進行設定,這里我們采用“訪問或拒絕”,那么這一段需求就變成“安全問題就是解決當前用戶能夠對資源對象進行訪問或拒絕控制的問題”,如果實現需要就是對功能進行控制還可以說成是“安全問題就是解決當前用戶能夠對功能進行訪問或拒絕控制的問題"。
一個簡單的設計
了解了問題的本質后,我們需要做的就是要完成它,那么怎樣來完成這呢。首先我們需要從需求之中將我們領域模型分離出來:
如果是一個簡單的權限設計,那么整個權限系統不這樣就完成了,非常的簡單明了(對于這里各對象所需要領域訪問就不在說明)。
基于角色的訪問
當簡單的設計使用的用戶數量一天一天的增加的時候,我們發現給一個一個用戶分別進行權限的設置是一件非常困難的工作。好,看來是我們修改設計的時候到了。最先想到的是我們必須對用戶進行分組,將對用戶的訪問授權設置到這些組之中。好,那我們就設置一個用戶組,通過用戶組來設置吧,但我們又會想到在實際的業務之中一個多崗的情況很多啊,那么怎么辦呢,同時如果能夠以現實際之中公司的實際情況設置權限最好不過,因為這樣對于系統的管理人員來說,只需要了解公司內部的情況就可以了,那么怎么樣來協調這兩個問題呢。
其實這個問題在安全設計的前輩們早已想到應對之策,就是將這些對象抽象以“角色”來表示這些抽象的概念。那么加入的角色對于我們的領域模型帶來了什么樣的變化呢?
這樣對于我們的管理來說真的大大的簡化了啊,但這就完全的滿足了我們的條件了嗎?
最初的數據權限
當我們正在為自己的設計而高興的時候新的問題又來了,怎么回事呢。小鄭啊,北美銷售部只能夠管理北美的銷售啊,發動機事業部只能夠銷售發動機產品啊,你那個程序是怎么回事啊,怎么都能夠看啊,還有怎么部長都能夠審批100W以上的定單啊。
啊,我快要完蛋了。
好,兵來將擋,水來土淹什么問題都能不倒我。
看來我們還必須要設計滿足數據權限的要求才行啊。
好吧,那我怎么樣子來實現呢...?好吧,我應在安全資源之中加一個數據規格,在訪問控制之中加入一個值的設定,怎么樣,這下行了吧?
好吧,現在就看我來實現它吧,以我精湛的技術。
啊,什么,一個用戶多個角色,不同的角色有不同的數據規則控制。啊,還需要數據控制的合并,沒事我們使用提供者模式來解決,實現不同的合并提供者,使用提供者來合并結果。
啊,什么,怎么樣轉換到數據訪問的控制,沒事,咱們硬編碼。
啊,不可能吧,連個獲取操作都需要進行控制啊。
啊,我不行了。倒在了黎民前了晚上。
更好的解決方法
如果沒有能夠對數據權限進行詳細的分析,那么一定會在倒在黎明的前夜,沒有完整的解決方法,那是不行的。好,我們先來分析一個數據權限的要求,這里我只能夠寫出我對于這部分的分析,數據權限的限制總是:{實體屬性值 條件 允許值}這三個產品分組成,如:數據規則,銷售部長只能夠審核銷售金額小于100W的定單這里的三者是{銷售定單.合計金額 小于 100W}, 銷售員小張只能夠銷售摩托車產品,這其中的三者是{銷售項目.產品類型 屬于 摩托車)
所以這里對于數據的限制都只包括三個要素:領域實體屬性 條件 允許值。這三者的結合就限制的約束。那么這三都之中都有哪些情況呢?
領域實體屬性:這個基本上都沒有什么變化。
條件:如果是條件就只有那么幾種,有大于,小于,等于,實體范圍等等。
允許值:允許值這里經過我的分析包括三種情況{設置值,用戶屬性相關值,業務設定值}
這三種情況分別使用于以下情況:設置值表示是我們是設置權限的時候直接進行設置的如100W,用戶屬性相關值表示與用戶的某一個屬性相關,如:部門,職務等。還有一種就是業務相關的情況,這類情況相當于是在業務之中設置數據。這類問題在SAP之中設置比較多,感興趣的可以去了解一下SAP之中的相關設置。
在這里對于條件的設置基本上都只有固定的幾種,可以采用枚舉的方式來進行,而對于充許值這一個點,因為不同的業務所需要的不同的數據和相關內容不想同,因此,將這一個允許值的獲取設置為一個相關的接口來進行,而在進行配置的時候只設置一個相關值,由接口去解晰和獲取。這時候的領域模型圖如下:
最后的戰役
在解決了領域問題之后,我們還需要考慮提供什么方式來獲取這些服務,這里首先需要考慮使用權限的兩種情況,一種是當需要顯示相關界面時; 二是當需要執行相關操作時。
- 第一種情況:當我們進入到提供定單的界面,那么顯示出來的相關產品肯定是我們能夠允許提供的產品,顯示出來的國家也是我們能夠進行銷售的國家。
- 第二種情況:當我們提交定單時,提供的內容必須進行檢查。
對于第一種情況:我們在執行GetCountries()和GetProducts()這兩個方式的內部就必須執行條件的限制,那么如何來實現這個條件的限制呢。這里必須要通過一種方式讓GetCountries了解到當前正自于那一個安全的環境之中,再獲取獲取相應的數據限制,查看這個限制的實體是否為Country如果是那么是那個條件進行的設置編號,國家名稱,上級部門。再將這些條件轉換為對應的SQL來進行限制,如果這些方法都是通過硬編號來完成,那么一定是一個復雜的工作,好在現在的ORM工具直接就支持領域實體,屬性,條件等內容,直接可以將這些配置的安全值設置到這些訪問之上,這樣就可以完成整個數據限制,同時還需要考慮到如果是在多個不同的應用之間設置這些服務,還需要考慮到安全的層次關系,在多個層次之中使用和設置多層安全環境。這就必須使用一個對應的環境管理類來管理這些環境。對于這個環境可以采用SecurityContext來表示,而對于這個環境的管理類使用SecrityContextManager的線程單例模式來進行設置。在實現的過程之中,如果需要一個新的安全環境則建立一個新的SecurityContext,在新實例的SecurityContext之中將自己注冊到SecurityContextManager的單實例之中。同時在建立SecurityContext時傳入相關的安全資源對象,對這些對象進行安全檢查,如果沒有進行授權則引發System.Security.SecurityException對象。
在開發數據訪問層時,通過SecurityContextManager.Instance來獲取如:Employee實體的的限制,通過前面所設計的獲取允許值提供者接口來獲取允許的值,并且將屬性,條件,允許值,轉換為對應的SQL來進行調用。這樣就實現了多層次的數據權限。如果對應的ORM工具能夠直接支持條件的設置則可以將這個工作直接編寫對應的轉換器來進行轉換,這樣可以大大的提高開發的效率,并且還可以根據需要對領域成員進行新的數據約束,而不必修改應用程序。
同時如果所需要限制的數據資源不是領域實體中的數據,也可以通過這種方式來設置自己的數據范圍的檢查。
總結
本文主要是介紹一種安全的實現方式,安全不是一個簡單到只需要在某一具體層就能夠解決的問題,而需要在多個層次進行多層次的設置。形成類似于IIS式的多層次,多角度權限設置,這里只是給出了其中最為核心的內容,沒有給出具體的代碼,這主要是因為不能夠公布公司內部開發的程序,所以可能對于完整的理解有所不足。
對本文有什么好的意見或見意請大家多指教。
鄭重聲明:本文版權歸原作者所有,轉載文章僅為傳播更多信息之目的,如作者信息標記有誤,請第一時間聯系我們修改或刪除,多謝。