1、转载:通过struts2拦截器实现权限管理
1.1简单实例:
避免login.jsp也被拦截,而永远不能登录了,一旦在某个包下定义了上面的默认拦截器栈,在该包下的所有 Action 都会自动增加权限检查功能,对于那些不需要使用权限控制的 Action ,将它们定义在另一个包中,这个新的包中依然使用 Struts 2 原有的默认拦截器栈,将不会有权限控制功能。
<package name="manage" extends="struts-default" namespace="/manage"> <!--配置系统烂机器--> <interceptors> <!-- 定义系统的登录控制的拦截器 --> <interceptor name="authority" class="com.Action.AuthorityInterceptor" /> <!--定义系统auctionStack烂机器--> <interceptor-stack name="auctionStack"> <!--引用系统默认拦截器--> <interceptor-ref name="defaultStack" /> <!--引用登录控制拦截器--> <interceptor-ref name="authority" /> </interceptor-stack> </interceptors> <!-- 将自定义连接器站定义成默认执行的拦截器 --> <default-interceptor-ref name="auctionStack" /> <global-results> <!-- 当返回login视图名时,转入/login.jsp页面 --> <result name="login" type="redirect">/login.jsp</result> </global-results> <action... </package> <package name="admin" extends="struts-default,manage" namespace="/admin"> <action name="login" class="com.dxz.SecurityAction" method="checklogin"> <result name"errorlogin">/login.jsp</result> <!--显示引用系统默认的烂机器 <interceptor-ref name="defaultStack"/> </action> <action name="loginout" ... </package>
AuthorityInterceptor.java
/** * */ package com.Action; import com.opensymphony.xwork2.ActionContext; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.interceptor.AbstractInterceptor; /** * @author duanxz//用户登陆权限验证; * */ public class AuthorityInterceptor extends AbstractInterceptor { public String intercept(ActionInvocation invocation) throws Exception { // 取得请求相关的ActionContext实例 ActionContext ctx=invocation.getInvocationContext(); if(ctx.getSession().get("userinfo")==null)//未登陆 { // return invocation.invoke(); return "login"; } return invocation.invoke(); } }
第一次使用,只是简单的测试,用户的session,作个标记。
1.2转载示例
package com.work.qxgl.login; import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletRequest; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.struts2.StrutsConstants; import org.apache.struts2.config.DefaultSettings; import com.opensymphony.xwork2.Action; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.interceptor.AbstractInterceptor; import com.work.core.QxglConstants; import com.work.core.spring.MyBeanUtil; import com.work.qxgl.model.QxglRole; import com.work.qxgl.usermodel.UserModelServiceDao; public class AuthorizationInterceptor extends AbstractInterceptor { /** * */ private static final long serialVersionUID = 4949812834762901805L; private static Log log = LogFactory.getLog(AuthorizationInterceptor.class); @Override public String intercept(ActionInvocation invocation) throws Exception { // 取得请求的Action名 String name = invocation.getInvocationContext().getName(); // action // 的名称,在xml中配置的 String namespace = invocation.getProxy().getNamespace(); // 获取到namespace,还能够获取到要执行的方法,class等 if ((namespace != null) && (namespace.trim().length() > 0)) { if ("/".equals(namespace.trim())) { // 说明是根路径,不需要再增加反斜杠了。 } else { namespace += "/"; } } String URL = namespace + invocation.getProxy().getActionName(); URL += ".action"; log.debug("actionname=" + name + "||fullActionName=" + URL); if (name.equals("login") || name.equals("loginAccess")) { // 如果用户想登录,则使之通过 return invocation.invoke(); } Map session = invocation.getInvocationContext().getSession(); // TODO 在这里判断用户是否已经登陆,更改此方法,和OnLineUserManager联系起来, //OnLineUserManager 是线程安全的,效率上可能会比较低!所以暂时还不更改!。 String success = (String) session.get(QxglConstants.AUTH_SUCCESS); log.debug("success=" + success); // 如果没有登陆,那么就退出系统 if (success == null || !"true".equals(success)) { log.debug("please login"); return Action.LOGIN; } String userid = (String) session.get("userid"); if (userid == null || "".equals(userid)) { log.error("用户id不能为空!"); return Action.LOGIN; } // 如果是超级管理员,那么直接返回 if ("admin1111222233334444555566admin".equals(userid)) { return invocation.invoke(); } UserModelServiceDao userModelServiceDao = (UserModelServiceDao) MyBeanUtil .getBean("userModelServiceDao"); // 获取当前用户所拥有的角色 List<QxglRole> userRoles = userModelServiceDao.getRoles(userid); if (userRoles == null || userRoles.size() < 1) { // 没有任何角色 log.warn("此用户" + userid + "没有任何角色,没有权限执行任何功能"); return "noPermit"; } List<QxglRole> urlRoles = userModelServiceDao.getRolesByUrl(URL); // 如果此URL没有赋给任何角色,说明是合法用户就可以访问 if (urlRoles == null || urlRoles.size() < 1) { log.debug("此资源未赋给任何角色,合法用户就可以访问"); return invocation.invoke(); } // 根据角色来判断用户是否有权限来使用当前的URL(action) boolean flag = false;// 如果有权限访问设置为true; int userLen = userRoles.size(); int urlLen = urlRoles.size(); QxglRole tempUserRole = null; QxglRole tempUrlRole = null; START: for (int i = 0; i < userLen; i++) { // 首先初始化 tempUserRole = null; tempUrlRole = null; tempUserRole = userRoles.get(i); for (int j = 0; j < urlLen; j++) { tempUrlRole = urlRoles.get(j); if (tempUserRole.getId().equals(tempUrlRole.getId())) { flag = true; break START; } } } if (flag) { log.debug("success auth"); return invocation.invoke(); } else { //用户如果在主页面中输入其他的任何链接,系统将自动执行logout动作,因为在/sysmenu/top.jsp中配置了onunload事件。 log.warn("此用户" + userid + "没有权限执行此功能"+URL); return "noPermit"; } }
}
在需要验证的包上加上配置,struts.xml
<package name="qxglmain" extends="struts-default" namespace="/"> <!-- 自定义拦截器 --> <interceptors> <interceptor name="auth" class="com.work.qxgl.login.AuthorizationInterceptor" /> <interceptor name="ourLogger" class="com.work.core.interceptor.LoggingInterceptor" /> <interceptor name="ourTimer" class="com.work.core.interceptor.TimerInterceptor" /> <!-- 自定义拦截器堆栈 --> <interceptor-stack name="qxglStack"> <interceptor-ref name="auth" /><!-- 权限控制 --> <!-- 用来查看每个action执行了多长时间,看执行效率,只所以重新编写,因为xwork的源代码的日志级别低为INFO,我们配置的日志级别为ERROR。所以看不到了 --> <interceptor-ref name="ourTimer" /> <interceptor-ref name="ourLogger" /> <!-- <interceptor-ref name="logger" /> --> <!-- 引用默认的拦截器堆栈 --> <interceptor-ref name="defaultStack" /> </interceptor-stack> </interceptors> <!-- 重定义默认拦截器堆栈 --> <default-interceptor-ref name="qxglStack" /> <global-results> <result name="login" type="redirectAction">login</result> <result name="error">/qxgl/error.jsp</result> <result name="noPermit">/qxgl/noPermit.jsp</result> <result name="input" type="redirectAction">login</result> </global-results> <!-- exception的配置必须在global-results后面 --> <global-exception-mappings> <exception-mapping exception="java.lang.NullPointerException" result="error" /> <exception-mapping exception="java.lang.Exception" result="error" /> <exception-mapping exception="com.work.core.exception.StorageException" result="error" /> </global-exception-mappings> <action name="qxglmain" class="com.work.qxgl.main.QxglMainAction"> <result>/qxgl/menutree/qxglmain.jsp</result> </action> <action name="sysmain" class="com.work.qxgl.main.QxglMainAction" method="sysmain"> <result>/sysmenu/sysMain.jsp</result> </action> <action name="login" class="com.work.qxgl.login.LoginAction" method="login"> <result>/login.jsp</result> </action> <action name="logout" class="com.work.qxgl.login.LogoutAction"> <result>/login.jsp</result> </action> <action name="loginAccess" class="com.work.qxgl.login.LoginAction"> <result type="redirectAction">sysmain</result> <result name="input" >/login.jsp</result> </action> <action name="listOnLineUsers" class="com.work.qxgl.login.OnLineUserAction"> <result>/qxgl/onlineuser/onlineuser.jsp</result> </action> <action name="kickUser" class="com.work.qxgl.login.OnLineUserAction" method="kickUser"> <result type="chain">listOnLineUsers</result> </action> <action name="listMenu" class="com.work.qxgl.main.QxglMainAction" method="listMenu"> <result>/sysmenu/menu.jsp</result> </action> </package>
缺点:
struts2的拦截器只能够控制*.action,其他的jsp文件等会被忽略,所以通过struts2的拦截器实现权限控制有一定的缺陷。
我们可以通过编写一个filter来控制其他请求的权限
package com.work.core.filter; /** * @author wangmingjie * @date 2008-8-25下午10:09:26 */ import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import com.work.core.QxglConstants; public class AuthFilter implements Filter { private static Log log = LogFactory.getLog(AuthFilter.class); public void init(FilterConfig filterConfig) throws ServletException { if(log.isDebugEnabled()){ log.debug("初始化权限过滤器。"); } } public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { /** * 1,doFilter方法的第一个参数为ServletRequest对象。此对象给过滤器提供了对进入的信息(包括 * 表单数据、cookie和HTTP请求头)的完全访问。第二个参数为ServletResponse,通常在简单的过 * 滤器中忽略此参数。最后一个参数为FilterChain,此参数用来调用servlet或JSP页。 */ HttpServletRequest request = (HttpServletRequest) servletRequest; /** * 如果处理HTTP请求,并且需要访问诸如getHeader或getCookies等在ServletRequest中 * 无法得到的方法,就要把此request对象构造成HttpServletRequest */ HttpServletResponse response = (HttpServletResponse) servletResponse; String currentURL = request.getRequestURI(); // 取得根目录所对应的绝对路径: HttpSession session = request.getSession(false); //如果jsp就验证(login.jsp除外) if (currentURL.indexOf(QxglConstants.LOGIN_PAGE)==-1 && currentURL.indexOf(".jsp")>-1 ) { if(log.isDebugEnabled()){ log.debug("对jsp文件进行权限验证。"+"请求的URL:"+currentURL); } // 判断当前页是否是重定向以后的登录页面页面,如果是就不做session的判断,防止出现死循环 if(session == null || session.getAttribute(QxglConstants.AUTH_SUCCESS) == null ){ response.sendRedirect(request.getContextPath()+QxglConstants.LOGIN_PAGE); return ; } } // 加入filter链继续向下执行 filterChain.doFilter(request, response); /** * 调用FilterChain对象的doFilter方法。Filter接口的doFilter方法取一个FilterChain对象作 为它 * 的一个参数。在调用此对象的doFilter方法时,激活下一个相关的过滤器。如果没有另 * 一个过滤器与servlet或JSP页面关联,则servlet或JSP页面被激活。 */ } public void destroy() { } }
在web.xml中配置权限过滤器
<!-- 进行权限验证 --> <filter> <filter-name>AuthFilter</filter-name> <filter-class> com.work.core.filter.AuthFilter </filter-class> </filter> <filter-mapping> <filter-name>AuthFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
2、配置编码过滤器
只需要导入spring.jar即可
<filter> <filter-name>CharacterEncoding</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> <init-param> <param-name>forceEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter> <filter-name>filterDispatcher</filter-name> <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class> </filter> <filter-mapping> <filter-name>CharacterEncoding</filter-name> <url-pattern>*.do</url-pattern> </filter-mapping> <filter-mapping> <filter-name>filterDispatcher</filter-name> <url-pattern>*.do</url-pattern> </filter-mapping>