想要做好許可權管理,並不是一件容易的事情,既要考慮授權的粒度保證安全,也要考慮授權的方式足夠便捷。之前有篇文章許可權管理系統設計介紹過我們的許可權設計,整體上是採用RBAC+資源隔離的方式,僅對小部分非常敏感的資料再透過物件授權的方式做管控。在實際的使用中也驗證了這樣的授權方式非常有效,尤其是多租戶模式-基於專案的資源隔離,授權方式足夠便捷,同時也有一定的粒度控制,畢竟大多數的情況下我們都是基於專案在管理資源,那基於專案去授權資源就很合適了
這樣的授權方案沒有問題,但是在授權方式上不夠完善,不完善的地方主要是在RBAC的授權上,由於後端採用Django框架,RBAC的授權就使用了Django的Auth模組來實現,只是把Group替換成了Role的概念,這樣就是User屬於Group/Role,Group擁有許可權,從而使用者也就有了相應的許可權。但這裡有一個問題,預設的Group沒有資源隔離的Project標識,這就導致了授權是全域性的,例如我給使用者A授予了主機檢視的許可權,他加入專案A就能檢視專案A下的主機,此時加入專案B同樣就會擁有專案B下資源檢視的許可權,這顯然是不合適的,需要能做到按專案的授權
舉一個實際的例子:使用者A是壓測中心的員工,會透過壓測系統對其他專案進行壓測,我們建個壓測的專案A,他是壓測專案A的owner,對壓測專案A擁有所有的許可權,例如資源檢視、釋出不熟等等。專案B有壓測的需求,使用者A就透過壓測系統對專案B進行壓測,此時使用者A需要檢視專案B被壓資源的監控資料,使用者A加入專案B,由於全域性許可權的存在,使用者A對專案B也就有了所有的許可權,這就是非常危險不可接受的,如何做到使用者A對壓測專案A擁有所有的許可權,而對被壓專案B僅有監控檢視的許可權呢?需要做到按專案去授權
道理都懂,如何實現?直接拋棄Django的Auth許可權認證系統自己實現,當然可以,不過改動太大,費時費力,當初使用Django就是看中了這些開箱即用的好功能。既然要結合專案去授權,那首先想到的實現方式跟我們做資源隔離一樣,預設的Group表加一個project欄位來標識專案,然後重寫許可權校驗的has_perm
方法,翻了下原始碼,擴充套件Group表不太好做,改動較大,同時也不是特別的合理。還是要拋棄空想,從實際出發看下系統和程式碼,仔細看了看,並不是所有的授權都適合與專案繫結,例如使用者系統相關的使用者管理許可權、多雲系統的多雲賬號管理許可權,這個本身就是全域性的,跟專案沒有什麼關係,那加個專案標識就沒有必要了,只有那些按專案做隔離的資源許可權適合與專案繫結,例如備份系統的備份任務許可權、多雲系統的資源管理許可權等
除此之外,在實際使用中還會有全域性授權的需求,例如部門經理對所有專案有所有許可權、監控工程師對所有專案有檢視監控的許可權。想清楚了這些使用場景,那就考慮,預設對許可權系統保持不變,作為全域性授權,同時擴充套件一個新的針對專案的許可權系統,作為專案授權,最終的許可權校驗會同時校驗全域性許可權和專案許可權,只要有其中之一為True,則就有許可權,實現起來也較為簡單
參考Django預設的Auth模組授權機制:User->Group->Permission,對於專案來說也是一樣的,專案成員表Member,Member關聯User表,專案角色表Role,Role也只是比Group表多了project欄位用來記錄所屬專案,許可權依然複用了Django預設Auth下的Permission表,此時的專案授權就是專案成員擁有專案角色,專案角色擁有相應許可權,這樣就能根據資料關係列出專案使用者擁有的專案許可權了
專案owner是一種特殊的角色,他擁有專案下的所有許可權,同時他也可以建立角色,為專案下的其他使用者賦權。這樣同時也做到了專案許可權管理的自助化,專案成員的許可權由專案owner負責,不需要再麻煩系統管理員,一個完整的使用者加入系統及授權流程如下
至此,RBAC+資源隔離,全域性授權+專案授權的機制趨於完善