在學習了struts2框架后,我萌生了一個想法:可不可以使用包(package)分配權限,而在攔截器中攔截到請求來檢測權限是否足夠?
ps:希望大家和我一樣喜歡多思考。不過在很長一段時間中我都以為是自己發明了這個技術……實際上很多項目都很好地應用了,只是一個小技巧而已……
廢話不多說,我先將struts.xml配置貼上來大家看看:
1 <?xml version="1.0" encoding="UTF-8" ?> 2 <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.1//EN" "http://struts.apache.org/dtds/struts-2.1.dtd"> 3 <struts> 4 <constant name="struts.enable.DynamicMethodInvocation" value="false" /> 5 <constant name="struts.ui.theme" value="simple" /> 6 <constant name="struts.i18n.encoding" value="UTF-8" /> 7 <!-- 默認包,定義公共屬性 --> 8 <package name="default" namespace="/" extends="struts-default"> 9 <interceptors> 10 <interceptor name="defaultInterceptor" class="web.interceptor.DefaultInterceptor" /> 11 <interceptor-stack name="defaultAll"> 12 <interceptor-ref name="defaultStack" /> 13 <interceptor-ref name="defaultInterceptor" /> 14 </interceptor-stack> 15 </interceptors> 16 <default-interceptor-ref name="defaultAll" /> 17 <default-action-ref name="defaultAction" /> 18 <global-results> 19 <result name="error">/WEB-INF/page/error.jsp</result> 20 <result name="login" type="redirectAction">toLogin</result> 21 <result name="toIndex" type="redirectAction">viewAllSubjects</result> 22 </global-results> 23 <action name="defaultAction"> 24 <result>/WEB-INF/page/error.jsp</result> 25 </action> 26 <action name="viewAllSubjects" class="web.controller.VoteAction" 27 method="viewAll"> 28 <result>/index.jsp</result> 29 </action> 30 <action name="viewOneSubject" class="web.controller.VoteAction" 31 method="view"> 32 <result>/WEB-INF/page/view.jsp</result> 33 </action> 34 <action name="vote" class="web.controller.VoteAction" method="view"> 35 <result>/WEB-INF/page/vote.jsp</result> 36 </action> 37 <action name="search" class="web.controller.VoteAction" method="search"> 38 <result>/index.jsp</result> 39 </action> 40 </package> 41 <!-- 注冊和登錄相關控制器 --> 42 <package name="loginandregister" namespace="/" extends="default"> 43 <action name="register" class="web.controller.UserAction" 44 method="register"> 45 <result>/WEB-INF/page/reg_success.jsp</result> 46 <result name="input">/WEB-INF/page/register.jsp</result> 47 </action> 48 <action name="login" class="web.controller.UserAction" method="login"> 49 <result type="redirectAction">viewAllSubjects</result> 50 <result name="input">/WEB-INF/page/login.jsp</result> 51 </action> 52 <action name="toRegister" class="web.controller.UserAction"> 53 <result>/WEB-INF/page/register.jsp</result> 54 </action> 55 <action name="toLogin" class="web.controller.UserAction"> 56 <result>/WEB-INF/page/login.jsp</result> 57 </action> 58 </package> 59 <!-- 管理員特權相關 --> 60 <package name="adminrights" namespace="/" extends="default"> 61 <action name="modify" class="web.controller.VoteAction" method="view"> 62 <result>/WEB-INF/page/saveorupdate.jsp</result> 63 </action> 64 <action name="saveVote" class="web.controller.VoteAction" 65 method="saveVote"> 66 <result>/WEB-INF/page/vote_success.jsp</result> 67 <result name="input" type="redirectAction">vote</result> 68 </action> 69 <action name="saveSubject" class="web.controller.VoteAction" 70 method="saveSubject"> 71 <result>/WEB-INF/page/saveorupdate_success.jsp</result> 72 </action> 73 <action name="addSubject"> 74 <result>/WEB-INF/page/saveorupdate.jsp</result> 75 </action> 76 <action name="modifySubjects" class="web.controller.VoteAction" 77 method="viewAll"> 78 <result>/WEB-INF/page/manage.jsp</result> 79 </action> 80 </package> 81 </struts>
上文就用包(package)將不同角色的可做操作“圈”到了一起。
ps:上文是一個在線投票系統的配置,在做項目時並未加入Spring,因為還沒學……
默認包中有一些公共的屬性和普通用戶需要登錄后才能進行的操作,實際上你可以使用多個包或使用嵌套的方式來約定包。
而上文引用的攔截器定義如下:
1 package web.interceptor; 2 3 import java.util.Arrays; 4 import java.util.Map; 5 6 import org.apache.struts2.dispatcher.Dispatcher; 7 8 import orm.VoteUser; 9 10 import com.opensymphony.xwork2.Action; 11 import com.opensymphony.xwork2.ActionContext; 12 import com.opensymphony.xwork2.ActionInvocation; 13 import com.opensymphony.xwork2.config.entities.PackageConfig; 14 import com.opensymphony.xwork2.interceptor.AbstractInterceptor; 15 16 /** 17 * 缺省或默認的攔截器,用於攔截用戶的未授權權請求 例如未登錄用戶的各種操作和普通用戶的權限分配 18 * 19 * @author Johness 20 * 21 */ 22 public class DefaultInterceptor extends AbstractInterceptor { 23 24 private static final long serialVersionUID = -2780681965998483504L; 25 26 /** 27 * 常量值:表示用戶用於登錄和注冊時請求的控制器所在包名 此值可以作為配置參數獲取,而此處使用了固定值 28 */ 29 private static final String PACKAGE_NAME_LOGINANDREGISTER = "loginandregister"; 30 /** 31 * 常量值:表示用於管理員用戶的特殊權限 此值可以作為配置參數獲取,而此處使用了固定值 32 */ 33 private static final String PACKAGE_NAME_ADMINRIGHTS = "adminrights"; 34 35 /** 36 * 登錄或注冊的請求“動作” 已登錄用戶不需要進行這些請求 此數組維護的控制器名稱需要依靠上文的參數動態獲取 37 */ 38 private static String[] loginAndRegister; 39 /** 40 * 管理員權限“動作” 普通用戶不能越權 此數組維護的控制器名稱需要依靠上文的參數動態獲取 41 */ 42 private static String[] adminRights; 43 44 /** 45 * 為上文數組填充數據 此方法中使用了一些固定值 46 */ 47 public void preData() { 48 Map<String, PackageConfig> map = Dispatcher.getInstance() 49 .getConfigurationManager().getConfiguration() 50 .getPackageConfigs(); 51 PackageConfig lar = map.get(PACKAGE_NAME_LOGINANDREGISTER); 52 if (null != lar && lar.getActionConfigs().size() > 0) 53 loginAndRegister = lar.getActionConfigs().keySet() 54 .toArray(new String[] {}); 55 else 56 loginAndRegister = new String[] { "toRegister", "toLogin", 57 "register", "login" }; 58 PackageConfig ar = map.get(PACKAGE_NAME_ADMINRIGHTS); 59 if (null != ar && ar.getActionConfigs().size() > 0) 60 adminRights = map.get(PACKAGE_NAME_ADMINRIGHTS).getActionConfigs() 61 .keySet().toArray(new String[] {}); 62 else 63 adminRights = new String[] { "addSubject", "saveSubject", 64 "modifySubjects", "modify" }; 65 66 // 因為要使用二分查詢,所以必須排序 67 Arrays.sort(loginAndRegister); 68 Arrays.sort(adminRights); 69 } 70 71 @Override 72 public String intercept(ActionInvocation arg0) throws Exception { 73 // 登錄用戶 74 VoteUser logUser = (VoteUser) ActionContext.getContext().getSession() 75 .get("logUser"); 76 // 請求的控制器名稱 77 String actionName = ActionContext.getContext().getName(); 78 79 // 如需要,則填充數據 80 if (null == loginAndRegister) 81 this.preData(); 82 83 // 如果用戶沒用登錄且並不請求登錄或注冊,則請用戶登錄 84 if (null == logUser 85 && Arrays.binarySearch(loginAndRegister, actionName) < 0) 86 return Action.LOGIN; 87 // 如果用戶已經登錄並請求登錄或注冊或者普通用戶請求管理員操作,則忽略用戶請求 88 if (Arrays.binarySearch(loginAndRegister, actionName) >= 0 || (logUser 89 .getVuVersion() == 0 && Arrays.binarySearch( 90 adminRights, actionName) >= 0)) 91 return "toIndex"; 92 return arg0.invoke(); 93 } 94 }
值得一提的是上文的攔截器屬性可以不定義為靜態,但是通過struts得到包和包內控制器名稱的方法在我的印象中似乎不能寫在靜態塊中(也許我記憶有誤)。而數據填充方式大家可以自定義,此類在一個Web進程中有一個實例即可。
代碼肯定是有待改進,不過好歹也是自己想到的並做到了,鼓勵一下吧。
(最后編輯時間2012-12-26 15:41:53)