看了網上一些關于權限控制的帖子,越看越迷糊,什么用AOP(Aspect Oriented Programming,面向方面編程),用容器,RBAC(基于角色的訪問控制方法),SSO,Jive的Proxy模式等等等等,且又是role又是group,真是頭都大了,先寫個簡單的實現方法,以后再研究高深的。
此方法不依賴容器框架,適用于小系統(主要JSP頁面要少于100,因為是硬編碼到JSP),適用于要精確控制頁面field的情況較多的系統。
(插句話:要分清權限控制與業務邏輯,業務邏輯就是情況由系統運行時的某些條件決定,如學生管理系統中,某一學生進入系統,只能看自己的記錄,因為可看的記錄是由學號來決定的,所以這是業務邏輯,而又如學生不能看老師的記錄,這是有學生的身份來決定的,所以這是權限控制。)
好了,進入正題!
建表:
user(user信息: userID userPassword 等)
role(role描述:roleID roleDesc)
permission(permission描述:permissionID permissionDesc)
user-role(user role對應關系表:userID roleID)
role-permission(role permission對應關系表:roleID permissionID)
user-permission(user permission對應關系表:userID permissionID)
重要申明:
1 此處role沒有繼承關系,只是permission的集合
2 user-permission表只是為了方便,其數據是根據user-role role-permission兩表得來,只有在user-role role-permission兩表有更新的時候更新此表,并不能單獨賦予user某個permission,只能賦予user一個或多個role。
3 permission的分配,這是一個難點,很多比較復雜的權限控制系統也是因為這個才發展出來,此處把它盡量想簡單,不考慮業務邏輯,以頁面為視角,分兩層,首先是需要控制的jsp頁面,然后是需要控制的頁面field(包括link,text,textbox,button等等),field這一層還有privilege之分(R和W,即可讀和可寫)
基本思路:進入JSP頁面時,檢查用戶信息,查到用戶有此permission就包含此代碼,如果沒有此permission就不包含此代碼,此功能由Tag來完成(不會寫Tag?不要緊,抄!)。看代碼吧!
1 建表(如上)
2 建兩個class(bean) (UserProfile是用戶基本信息 UserPermission是permission )
UserProfile.java:
package com.××.××.××;
import java.util.Collection;
public class UserProfile {
private String userId;
private String userType;
private String companyNo;
private String companyName;
private String companyType;
private Collection userPermissions;
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getUserType() {
return userType;
}
public void setUserType(String userType) {
this.userType = userType;
}
public String getCompanyNo() {
return companyNo;
}
public void setCompanyNo(String companyNo) {
this.companyNo = companyNo;
}
public String getCompanyName() {
return companyName;
}
public void setCompanyName(String companyName) {
this.companyName = companyName;
}
public String getCompanyType() {
return companyType;
}
public void setCompanyType(String companyType) {
this.companyType = companyType;
}
public Collection getUserPermissions() {
return userPermissions;
}
public void setUserPermissions(Collection userPermissions) {
this.userPermissions = userPermissions;
}
}
UserPermission.java:
package com.××.××.××;
public class UserPermission {
private int permissionId;
private String privilege;
public int getPermissionId() {
return permissionId;
}
public void setPermissionId(int permissionId) {
this.permissionId = permissionId;
}
public String getPrivilege() {
return privilege;
}
public void setPrivilege(String privilege) {
this.privilege = privilege;
}
}
3 加兩個Tag(Page與Field):
SecurityTagForPage.java:
package com.**.**.taglib;
import java.util.*;
public class SecurityTagForPage extends TagSupport{
private int permissionID;
public int doEndTag() throws JspException{
HttpSession session = pageContext.getSession();
//登陸時把該user的userProfile放到session里
UserProfile userProfile = (UserProfile)session.getAttribute("userProfile");
Collection collection= userProfile.getUserPermissions();
Iterator it = collection.iterator() ;
while(it.hasNext()){
UserPermission userPermission = (UserPermission)it.next();
if ((permissionID == userPermission.getPermissionId())){
return EVAL_PAGE;
}
}
return SKIP_PAGE;
}
public int getPermissionID(){
return permissionID;
}
public void setPermissionID(int permissionID){
this.permissionID = permissionID;
}
}
SecurityTagForField:
public class SecurityTagForField extends TagSupport{
private int permissionID;
private String privilege;
public int doStartTag() throws JspException{
HttpSession session = pageContext.getSession();
UserProfile userProfile = (UserProfile)session.getAttribute("userProfile");
Collection collection= userProfile.getUserPermissions();
Iterator it = collection.iterator() ;
while(it.hasNext()){
UserPermission userPermission = (UserPermission)it.next();
if (privilege ==null){
if ( (permissionID == userPermission.getPermissionId())){
return EVAL_BODY_INCLUDE;
}
}else{
if ((permissionID == userPermission.getPermissionId())
&&(privilege.equals(userPermission.getPrivilege()))){
return EVAL_BODY_INCLUDE;
}
}
}
return SKIP_BODY;
}
public int getPermissionID(){
return permissionID;
}
public void setPermissionID(int permissionID){
this.permissionID = permissionID;
}
public String getPrivilege(){
return privilege;
}
public void setPrivilege(String privilege){
this.privilege = privilege;
}
}
4 在web-inf目錄下建個securityTag.tld文件,內容如下:(改一下class的目錄)
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN"
"http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd">
<!-- a tag library descriptor -->
<taglib>
<tlibversion>1.0</tlibversion>
<jspversion>1.1</jspversion>
<shortname>security</shortname>
<uri/>
<info>access control!</info>
<tag>
<name>securityForField</name>
<tagclass>com.companyname.prjname.taglib.SecurityTagForField</tagclass>
<attribute>
<name>permissionID</name>
<required>true</required>
</attribute>
<attribute>
<name>privilege</name>
</attribute>
</tag>
<tag>
<name>securityForPage</name>
<tagclass>com.companyname.prjname.taglib.SecurityTagForPage</tagclass>
<attribute>
<name>permissionID</name>
<required>true</required>
</attribute>
</tag>
</taglib>
5 修改需要控制的jsp
在jsp頁面這樣寫:
<%@ taglib uri="/WEB-INF/securityTag.tld" prefix="security" %>
<%@ page import="com.hp.elog2.util.Util" %>
<security:securityForPage permissionID="36" />
.......
<security:securityForField permissionID="46" privilege="R">
<td><html:text name="formBean" property="property1" readonly="true" /></td>
</security:securityForField>
<security:securityForField permissionID="46" privilege="W">
<td><html:text name="formBean" property="property1" /></td>
</security:securityForField>
......
這樣就大功告成了,建議在所有jsp頁面完成后再做權限控制這一塊(添加Tag),主要都是些Copy+C和Copy+V的工作。
此方法最大的問題就是hardcode太多,但結構簡單,思路清晰,適用范圍廣。
復雜的方法希望同道之士于我聯系leon_sandy@tom.com,共同研究!