在学习了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)