這里有必要先對權限控制方式本身做一下討論,有些系統用菜單進行權限控制,比如"新建客戶","瀏覽客戶",往往用操作名加上一個資源名代表一個權限,這樣的權限控制有一個缺陷,就是一般漏掉了一個資源范圍,比如瀏覽什么樣的客戶,就沒有說明。當然也可以加上,比如瀏覽個人客戶,瀏覽部門客戶,瀏覽公司客戶,但是隨著需要控制資源類型的增加,通過不斷增加菜單項來進行控制,并不是一個很好的方法。在B/S系統中的菜單控制,有2重意義,一是真正的菜單,沒有權限的用戶就看不到相應的菜單項,另外一個為了防止用戶任意提交信息,在服務器端對用戶提交的URL進行檢查,看是不是有這個權限。比如對于用戶請求的ListCus.do就要先檢查用戶是否有訪問這個URL的權限: public class ListCusAction extends Action{ ... public ActionForward execute(...){ ... //必須提供這樣的檢查的方法。 PermitUtil.checkPermit(userID,url); list = dao.query(sql); ... } } 另外一種控制辦法是對操作和操作資源定義權限,比如用戶A可以對客戶進行修改操作。這樣細粒度的權限控制對程序的擴展性和安全性有很大好處,但實現比前一種費時,下面通過分析說明2種方式的特點。
作為客戶系統最簡單的一種考慮,是每個用戶治理自己的客戶。這種請況下,我們通過在Customer表中增加一個用戶字段,就可以知道這個客戶對應于哪一個用戶。如下面的類所示: public class Customer{ PRivate String ctmNo; private String ctmName; ... private String userID; //getters and setters } 那么通過菜單的控制方式,我們認為每個有客戶創建權的用戶都可以創建屬于自己的客戶,什么叫客戶創建權,就是可以看到和選擇“添加客戶”菜單項的用戶。同時,“客戶瀏覽”就表示瀏覽屬于自己的客戶,這樣一來,創建客戶的用戶可以看到自己的客戶,并進行操作,我們通過菜單控制權限方式完成了這個需求。需要注重的是:在用戶進行相應操作前,我們先判定這個客戶是不是屬于這個用戶,是就可以操作,不是就不可以。如下例所示: public class DelCusAction extends Action{ ... public ActionForward execute(...){ ... //必須提供這樣的檢查的方法。 dao.checkPermit(customer,userID); dao.delete(customer); ... } } 進行這個判定是出于安全性考慮的,非凡在B/S架構的軟件系統中,你無法阻止客戶向服務器端任意提交信息。比如用戶A不使用菜單,向服務器請求"DelCus.do?ctmNo=No1",而No1屬于用戶B,假如不進行判定,客戶就被刪除掉了。所以光靠控制菜單項的顯示完成權限控制,并不完整。
現在我們接觸一個更復雜一點的需求,就是客戶轉移,把客戶從一個用戶,指派給另外一個用戶。在上面的實現基礎上,只要添加一個接口,改變客戶所屬的用戶,問題也就解決了。如下: public class ChangeUserAction extends Action{ ... public ActionForward execute(...){ ... dao.checkPermit(customer,userID); //改變客戶所屬用戶到newUserID。 dao.changeUser(customer,newUserID); ... } }
每個用戶現在可以治理自己的客戶,也可以把客戶交給別人治理,問題解決得完美。我們再考慮實際的情況,一個客戶可能可以被一個用戶看,但是不可以被修改或者刪除。我們怎么控制這樣的權限,加一個菜單項-"察看客戶",用戶A可以執行這個操作,但是不可以選擇菜單項-"修改客戶",針對每一個動作,我們加了一個菜單項。我們需要控制的內容變得越來越多。再深入分析,可以發現,其實上面的方案已經不能滿足需求。 2個客戶我們如何知道一個可以被用戶A看,一個不可以,出現了一個資源的治理問題,必須有另外的方案來進行這種權限的控制。我們設計一個資源類: public class CustomerResource{ //客戶編號 private String ctmNo; //操作類型 private String action; //用戶 private String userID; //setters and getters. } 再設計一個資源治理類: public class CustomerResourceManager{ private static List resources; private static void addResources(CustomerResource resource){ resources.add(resource); } //從數據庫裝載相應用戶的客戶操作權限。 private static void retrieveResources(String userID){ ... } //檢查相應的權限是否在resources中存在。 private static boolean checkPermit(CustomerResource permit){ ... } } 客戶端使用類: public class DelCusAction extends Action{ ... public ActionForward execute(...){ ... //必須提供這樣的檢查的方法。 CustomerResource resource = new CustomerResource(); resource.setCtmNo(customer.getCtmNo()); resource.setAction("DELETE"); resource.setUserID(userID); if(CustomerResourceManager.checkPermit(resource)){ dao.delete(customer); } ... } } 在采用了上面的權限檢查方式后,我們可以對每一個客戶指定相應操作人的權限,對客戶的操作就限制在了操作類型的多少上,基本的有“UPDATE,INSERT,DELETE,LIST,VIEW”等,其余也可以定義“SUBMIT”等操作,具體取決于系統需求。這樣的好處是權限控制非常靈活,客戶可以作為資源在用戶之間自由流動。但是作為一個給用戶最終使用的權限系統,這樣的卻體系不適合于出現在用戶權限系統設置里面,不能叫每個用戶都去自己指定自己創建客戶的操作范圍,最好是通過這種方式實現默認的業務和權限設定,滿足了用戶需求,又屏蔽復雜性。在完整的系統中,基于菜單的控制也是必不可少,這樣的方式方便用戶使用,也更易于用戶理解。 2者通常應結合使用。