權限管理 (一) 設計思路分析和實現受權、認證

  1. 權限的認識
    1. 提及對權限的理解能夠說是從膚淺到了解,如今也只是處在瞭解的水平,先來看這樣一個通俗且真實的故事:咱們都知道在有體制的公司或者機關單位,給人的體制化特別突出,通俗的說就是官大一級壓死人,上級的權利每每要比下面人大,有什麼事情了須要通過上級審批、贊成纔可以執行,這也是一種法律程序,不少事情都須要走法律流程。
    2. 你沒有在領導的位置上有些事情你說了就不算須要領導贊成,若是某天你的上司說「這件事你說了算,由你負責」這就是把管這事的權利交給你,叫受權;而後,和這件事打交道的人員須要確認誰管這事,這就叫作認證。權限也就是受權和認證的過程。
    3. 在作機房系統中一樣也涉及到了權限,系統中分了三類人員管理員、操做員和通常用戶,須要根據不一樣類型的人員顯示不一樣的界面模塊,當初實現的時候僅僅是在界面層作了一個簡單的判斷作的很是粗糙,只是簡單的顯示出人員對應的模塊沒有深刻的進行控制,如一個模塊的增刪改查控制,若是該人員對應的模塊顯示出來了就會有該模塊的全部權限,不夠靈活。
    4. 隨着作的系統逐步變大、模塊也增多了咱們引入了角色一詞表示一組權限的集合,至關於根據實際需求把權限分了「類」分紅一組一組的,能夠將一組權限授予用戶,如此一來,不須要一個個的授予用戶變的方便了。固然也能夠給某一個用戶單獨受權。
    5. 權限設計的目標是設計出這樣的系統界面:用戶受權、認證、模塊動態顯示等,這部分對於系統的安全性相當重要,所以,權限設計很是重要,也有一些成熟的模型解決權限管理,下面咱們來介紹一種實現解決方案:
  2. 實現思路和需求
    1. 把各個模塊、角色、用戶抽象出來各對應一個實體類,讓用戶或角色與模塊關聯並增長屬性控制增刪改查,這很像是一個M:N的對應關係又往中間一個關係上添加屬性,受權的過程當中主要經過角色給用戶受權,特殊的也能夠給用戶單獨受權。
    1. 用戶(User)能夠擁有多個角色(Role),角色能夠被分配給多個用戶
    2. 權限的意思就是對某個資源的某個操做,如今規定:
      1. 所謂資源,即系統的模塊
      2. 所謂操做,包括:增長、刪除、修改、查詢等操做
    3. 權限管理系統的整體功能分爲:受權與認證
    4. 受權,指將權限授予角色或用戶
      1. 若是用戶A擁有角色B、角色C,那麼,缺省的狀況下,用戶A將擁有被分配給角色A和角色C的全部權限(即默認狀況下,用戶A繼承其擁有的角色所具備的全部權限)
      2. 若是用戶擁有多個角色,那麼用戶的權限是這些角色權限的合集
      3. 若是用戶擁有多個角色,並且角色之間的受權有衝突(好比對同一個資源的同一個操做,一個角色爲「容許」,另一個角色爲「不容許」),將以優先級別高的角色爲準(所謂優先級別,也就是對於這個用戶所擁有的角色而言,是有順序的,同一個角色在不一樣的用戶那裏可能擁有不一樣的優先級)
      4. 除了能夠對角色進行受權外,也能夠針對用戶進行受權,也就是說,將權限授予用戶。針對某個資源的全部操做,咱們能夠設置這些權限對用戶來講是「繼承」或「不繼承」
        1. 繼承:意思是這些權限將使用其(即用戶)所擁有的角色的權限,而不使用其(即用戶)單獨設置的權限
        2. 不繼承:意思是這些權限將使用其單獨設置的權限,而不使用其所擁有的角色的權限
    5. 認證,指用戶訪問資源的某些操做時,根據受權,判斷是否容許用戶的訪問
      1. 在用戶訪問的時候,須要進行即時的判斷(是否有權訪問)
      2. 應該提供查詢的功能,能夠查詢某個用戶所擁有的全部權限
  3. 抽象實體類
    1. 爲了實現生面需求,抽象出來了下面這些實體類,這張類圖是主要的實體對象,能夠實現權限控制。
    2. ACL
    3. 圖中主要不易理解的是ACL類,該類表示訪問控制列表(access control list),具備用戶或角色與模塊的關聯關係以及它們的操做標識符,其中,操做標識符利用int的二進制表示,javaint32位能夠用其中任意四位表明CRUD,爲了方便一些使用最右邊四位表示,表示是否有操做權限。
    4. 用戶還能夠從角色那裏繼承權限,咱們在ACL類中新增長一個int屬性表示角色是否被繼承,在UsersRoles關係中加入一個字段表明角色的優先級,解決不一樣角色擁有相同模塊時的衝突問題。
  4. 實現
    1. 受權的過程即把模塊的訪問權授予用戶或者角色。
    1. 某一模塊受權或者取消受權的代碼
    1. 	public void setPermission(int permission,boolean yes){
      		int tmp =1;
      		
      		tmp=tmp << permission;
      		if (yes) {
      			aclState |= tmp;
      		}else {
      			aclState &= ~tmp;
      		}
      	}


    2. 例如setPermission(1,true)表示授予 read 權限,一個int temp = 1的臨時變量, aclState爲原始受權狀態,tmp的二進制表示是: 00000000 00000000 0000000000000001,tmp左移1位獲得read。temp = tmp < < 1; temp變成:00000000 00000000 00000000 00000010,而第二位表明的就是read權限。因此也能得出,左移0、一、二、3就能獲得Create、Delete、Update、Select權限。
    3. 假設原始受權aclState=00000000 00000000 0000000000001010,當變量yes=true時,爲受權,將temp與aclState求|運算,由於temp如今只有他要受權的位爲1,求或運算後,aclState=0000000000000000 00000000 00001010,這樣就受權成功.
    4. 當變量yes=false時,爲取消受權,先將temp取反,即爲1111111111111111 11111111 11111011,如今只有要取消權限的位爲0,其他全爲1,而後與aclState求&運算,則除了要取消權限的位變0,其他的都不變,即aclState=0000000000000000 00000000 00001010.
    1. 受權流程

      1. 	/**
        	 * 受權:對角色或者用戶
        	 */
        	public void addOrUpdatePermission(String principalType, int principalSn,
        			int resourceSn, int permission, boolean yes) {
        		//根據主體表示和資源表示查找ACL實例
        		ACL acl=findACL(principalType, principalSn, resourceSn);
        		//若是存在則更新ACL實例,更新受權
        		if (acl!=null) {
        			acl.setPermission(permission, yes);
        			getHibernateTemplate().update(acl);
        			return;
        		}
        		//若是不存在則建立新的實例
        		if (acl==null) {
        			
        			acl=new ACL();
        			acl.setPrincipalType(principalType);
        			acl.setPrincipalSn(principalSn);
        			acl.setResourceSn(resourceSn);
        			acl.setPermission(permission, yes);
        			getHibernateTemplate().save(acl);
        		}
        	}


    1. 認證流程
      1. 	public int getPermission(int permission){
        		
        		if (aclTriState == 0xFFFFFFFF) {
        			return ACL_NEUTRAL;
        		}
        		
        		int tmp=1;
        		tmp=tmp << permission;
        		tmp &= aclState;
        		if (tmp !=0) {
        			return ACL_YES;
        		}
        		return ACL_NO;
        		
        	}



      2. 	public boolean hasPermission(int userId, int resourceSn, int permission) {
        
        		//查找對特定用戶的受權
        		ACL acl=findACL(ACL.TYPE_USER, userId,resourceSn);
        		if (acl!=null) {
        			int yesOrNo=acl.getPermission(permission);
        		
        			//若是是肯定的受權
        			if (yesOrNo != ACL.ACL_NEUTRAL) {
        				return yesOrNo==ACL.ACL_YES ? true:false;
        			}
        		}
        		//繼續查找用戶的角色受權
        		String hql="select r.id from UsersRoles ur join ur.user u join ur.role r "+
        					"where u.id=? order by ur.orderNo";
        		
        		List aclIds=getHibernateTemplate().find(hql,userId);
        		//依照角色的優先級依次查找其受權
        		for (Iterator iter = aclIds.iterator(); iter.hasNext();) {
        			Integer rid = (Integer) iter.next();
        			acl=findACL(ACL.TYPE_ROLE,rid, resourceSn);
        			
        			//一旦發現受權,便可返回結果
        			if(acl!=null){
        				return acl.getPermission(permission) == ACL.ACL_YES ?true:false;
        			}
        		}
        		return false;
        	}


  5. 上面是從瞭解權限到一個權限模塊的解決思路和設計步驟,在大小不一樣的系統中能夠適當的擴展和刪減,這只是一種思路還有不少關於權限的解決方法好比RBAC等。
相關文章
相關標籤/搜索