聊聊數據權限哪些事兒
來自: http://my.oschina.net/tinyframework/blog/630801
序
一般來說,權限有許多種,我們經常用到的一般有操作權限和數據權限兩種。
所謂操作權限就是有或者沒有做某種操作的權限,具體表現形式就是你看不到某個菜單或按鈕,當然也有的是把菜單或按鈕灰掉的形式。實際上它的實現機制比表面上看到的要復雜得多,比如:我們從瀏覽器訪問過一個地址之后,實際上這個URL就會在歷史中存在,這時就會存在一種可能,有的人雖然沒有權限,但是他知道怎么訪問的URL,如果他再有一定的技術基礎,那么通過猜測,有時候就可以得到真正的操作的URL,這個時候如果操作權限限制做得不到位,那么他就可能做他非授權的事項,所以操作權限一般都在顯示界面做一次控制,過濾沒有權限的操作菜單或按鈕,另外在真正執行操作時,還要進行一次權限檢查,確保控制非授權訪問。
所謂數據權限,就是有或者沒有對某些數據的訪問權限,具體表現形式就是當某用戶有操作權限的時候,但不代表其對所有的數據都有查看或者管理權限。數據權限有兩種表現形式:一種是行權限、另外一種是列權限。所謂行權限,就是限制用戶對某些行的訪問權限,比如:只能對本人、本部門、本組織的數據進行訪問;也可以是根據數據的范圍進行限制,比如:合同額大小來限制用戶對數據的訪問。所謂列權限,就是限制用戶對某些列的訪問權限,比如:某些內容的摘要可以被查閱,但是詳細內容就只有VIP用戶才能查看。通過數據權限,可以從物理層級限制用戶對數據的行或列進行獲取,這種方式比把所有數據拿到之后再根據用戶權限來限制某些行或列有諸多好處:
- 性能提升:獲取的數據量較少,節省了網絡流量和數據庫IO,一定程度上可以提升性能
- 翻頁處理更為準確:如果通過后續邏輯去掉某些行,就會導致一頁顯示的記錄條數不足,或者采用這條記錄只顯示部分內容,但是操作權限方面做限制的方式,這個時候就產生一個悖論,你不想讓我操作,為什么讓我看到?你讓我看到為什么不讓我操作?
- 安全風險提升:理論上讓攻擊者看到的信息越多,被攻擊的風險也越大。通過后續業務邏輯限制的方式通過攻擊控制層或展現層的代碼,理論上就可以獲取到所有的數據。
- 代碼編寫工作量增加:由于數據是正常全部返回的,只是通過后期的邏輯進行了控制,這個時候就需要開發人員增加相關的代碼來進行判斷和控制,這個時候會把高層級的限制邏輯暴露給底層業務開發人員,并由他們來編寫代碼進行限制。
- 代碼重構工作量增加:當權限限制邏輯或范圍有變化的時候,程序員們就需要對這部分邏輯進行重構,稍不注意就會出現數據安全問題。
操作權限相對來說比較簡單,目前也有比較好的解決方案,因此今天的不討論操作權限,今天重點來討論數據權限的實現方案。
需求整理
一個好的數據權限方案要考慮哪些問題呢?我覺得要考慮以下方面:
- 對程序員透明:整個方案對于程序員們來說,不論是前臺還是后臺的程序員們來說,越透明越好,他們最好不知道有這么回事情
- 與不同的用戶權限能較好集成:作為一個數據權限系統來說,肯定要和用戶、角色、組織機構什么的數據打交道。如果這個方案只能和某一種用戶權限系統集成,那么它充其量只能算是一個可用的解決方案,但是注定算不是上好的解決方案。
- 性能損失最少:我們說,要增加新的功能或限制的過程中,肯定會對性能方面有一定影響的,怎么樣能把性能損失降低,甚至能提升一定的性能是設計師們永恒的主題。
- 對于分頁能良好支持:上面有說到當采用了行權限時,有些行是不能顯示給用戶的,這個時候不能對分頁有影響,比如本來是一頁是10條的,現在忽然變成8條,甚至在極端情況下變成0條,這樣的用戶體驗就非常差了。
- 一次設定到處生效,哪怕是不同的ORMapping方案也都起作用:我們知道,現在采用唯一的一種ORMapping解決方案的場景已經越來越少了,不同的方案都有自己的優缺點,它可能只適應某種前置條件下的應用場景,實際應用的情況下根據場景不同使用不同的解決方案也是非常普遍的,這就要求解決方案有一定的普適定。
- 跨數據庫:一個項目,它的運行環境基本上是確定的。但是對于一個產品來說,根據用戶的實際場景不同,可能對于數據庫也有不同的要求,這個時候就需要對不同的數據庫有支持,不能對于A數據庫是支持的,對于B數據庫的場景下,就出異常或者結果不正確了。
需求分析
由于要對程序員透明,因此解決方案不應該在DAO層實現。
由于要和不同的用戶權限系統進行集成,因此確定了不能在DAO層實現。
對于分頁有良好的支持,決定了不能在DAO層和顯示層實現。
一次設計到處生效,對多種ORMapping方案生效,決定了不能在ORMapping層實現。
要求能跨數據庫,進一步提升了方案的通用性和普適性,也提升了實現的難度。
數據行權限不是所有的過濾條件都是和用戶、角色、崗位字段有關的,不是所有的表中,都有用戶、角色、崗位字段,這個時候也要能良好支持。比如:人員信息表中:不同的級別的HR,可以看到不同級別的人員信息。總之過濾條件可能是數據表中的任意字段。
數據列權限是控制列的可見性的,也就是說,同樣對這行數據有權限,但是可能對其中的幾列沒有權限,則這幾列不可見。
比如表table1 有(a,b,c,d,e,f)字段,列權限控制可能控制c,d不可見。但是程序員寫代碼的時候可能寫的是select * from table1,這種情況下也不能返回c,d字段。
實現思路
呵呵,估計現在已經把許多方案已經逼到垃圾堆了。說實際關于這個主題,我也思考了相當長的時間,一直沒有好的解決辦法。因為我自己給出了N個解決方案,又都被自己所推翻,因為這些方案距離我期望的方案都有相當的距離。
直到有一天,開一個無聊的會,然后就走神了,忽然之間冒出一個想法,然后仔細品味一下,貌似可以講通,于是和開發人員進行了一下推演,技術實現上沒有什么問題, 那就先做一版出來再說。
下面簡單說一下思路,真正的實現思路將在真正實現之后再行補充。
歸根到底,數據權限的實現思路就是個調整SQL的問題,直白點就是做加減法的問題。
對于行權限來說無非是把一部分SQL條件附加到程序員寫的SQL語句中,對于列權限來說則是把程序員寫的SQL語句一部分從SQL里減去的問題。
然后問題就轉化為在哪一層里對程序員的SQL進行處理的問題,由于上面在提需求的時候附加了一系列的條件,因此也就確定了這一層不可能在DAO層,也不可能在ORMapping層來解決,這個時候可以添加層次就和分庫分表方案一樣了,只能在JDBC層或者協議代理層來解決,相對來說協議代理層離得太遠了,因此在JDBC層就是一個合適的選項。
上面一段說離得太遠,是指在應用中,這些 SQL的加減需要根據當前登錄人員的身份進行判定,在代理層要獲得當前登錄人員的信息會非常復雜,因此會增加額外的復雜度,確實是離得太遠。但是在JDBC層做起來就方便多了。
在JDBC層來進行處理,有幾個好處,第一:所有的SQL語言,不論用得什么ORMapping方案,最后總是繞不過這一層的;第二、這一層實現的話,對于開發人員來說是全透明的;第三、這一次離業務實現足夠近,可以比較方便的獲得當前登錄用戶的相關信息。
故事講到這里,整個實現方案已經沒有什么懸念了:通過在JDBC層對要處理的SQL語言進行解析,然后根據定義好的數據權限規則對SQL進行處理,通過增減SQL片斷,使之達成數據權限控制的目的。
總結
通過上面對問題的分析,需求的整理,需求的分析及設計思路的思考,我就對數據權限的來龍去脈及其解決方案進行了比較深入的分析,親們可以根據我的思路自行實現,也可以期待我們實現。
注意:本方案只針對JavaEE場景,對于非JavaEE不能保持方案的可實現性。
如果你喜歡我的博客,請點擊左上角的關注,這樣就可以第一時間獲得我的第一手信息,也歡迎查閱我的其他博客,絕對值得一看。