需要实现的功能:判断用户是否已登录,未登录用户禁止访问任何页面或action,自动跳转到登录页面。

过程:因为对过滤器和拦截器都不熟悉,开始两种方式都问题不断,后调试通过,贴在这里留作小结和备忘

过滤器filter实现

配置:web.xml


1. <filter>  
2. <filter-name>RightFilter</filter-name>  
3. <filter-class>com.***.rights.RightFilter</filter-class>  
4. </filter>  
5. <filter-mapping>  
6. <filter-name>RightFilter</filter-name>  
7. <url-pattern>*.jsp</url-pattern>  
8. </filter-mapping>  
9. <filter-mapping>  
10. <filter-name>RightFilter</filter-name>  
11. <url-pattern>*.action</url-pattern>  
12. </filter-mapping>


代码:


 


    1. mport java.io.IOException;  
    2.   
    3. import javax.servlet.Filter;  
    4. import javax.servlet.FilterChain;  
    5. import javax.servlet.FilterConfig;  
    6. import javax.servlet.ServletException;  
    7. import javax.servlet.ServletRequest;  
    8. import javax.servlet.ServletResponse;  
    9. import javax.servlet.http.HttpServlet;  
    10. import javax.servlet.http.HttpServletRequest;  
    11. import javax.servlet.http.HttpServletResponse;  
    12. import javax.servlet.http.HttpSession;  
    13.   
    14. public class RightFilter extends HttpServlet implements Filter {  
    15.   
    16.     public void doFilter(ServletRequest arg0, ServletResponse arg1,  
    17.             FilterChain arg2) throws IOException, ServletException {  
    18. response = (HttpServletResponse) arg1;    
    19. request=(HttpServletRequest)arg0;  
    20. session = request.getSession(true);    
    21. usercode = (String) session.getAttribute("usercode");//  
    22. url=request.getRequestURI();  
    23. usercode==null || usercode.equals(""))  
    24.         {  
    25.             //判断获取的路径不为空且不是访问登录页面或执行登录操作时跳转  
    26. <0 && url.indexOf("login")<0 ))  
    27.             {  
    28.                 response.sendRedirect("登录路径");  
    29.                 return ;  
    30.             }             
    31.         }  
    32.             //已通过验证,用户访问继续  
    33.             arg2.doFilter(arg0, arg1);  
    34.             return;  
    35.     }  
    36.   
    37.     public void init(FilterConfig arg0) throws ServletException {  
    38.         // TODO Auto-generated method stub  
    39.   
    40.     }



    配置中的filter-mapping,定义的是需过滤的请求类型,上面的配置即过滤所有对jsp页面和action的请求。过滤器的实现与struts2、spring框架无关,在用户请求被相应前执行,在过滤器中,可使用response.sendRedirect("")等方法

    跳转到需要的链接,如登录页面、错误页面等,不需要跳转时,arg2.doFilter(arg0, arg1);即可继续执行用户的请求。注意使用filter时避免连续两次跳转,否则会报java.lang.IllegalStateException错误,具体配置方法网上有,除非必要,不建议使用/*(过滤所有访问)的配置方式,这样配置,图片、js文件、css文件等访问都会被过滤

    拦截器interceptor实现:

    配置:struts.xml


    1.   <interceptors>    
    2. <!--定义一个名为authority的拦截器-->    
    3. <interceptor  class="com.***.rights.RightInterceptor" name="rightInterceptor"/>    
    4. <!--定义一个包含权限检查的拦截器栈-->    
    5. <interceptor-stack name="mydefault">    
    6. <!--配置内建默认拦截器-->    
    7. <interceptor-ref name="defaultStack"/>    
    8. <!--配置自定义的拦截器-->    
    9. <interceptor-ref name="rightInterceptor"/>    
    10. </interceptor-stack>    
    11. </interceptors>    
    12. <default-interceptor-ref name="mydefault" />    
    13. <!--定义全局Result-->    
    14. <global-results>   
    15. <result name="login">Login.jsp</result>    
    16. <result name="error">/error.jsp </result>   
    17. </global-results>


    代码:



      1. import java.util.HashMap;  
      2. import java.util.Map;  
      3. import com.opensymphony.xwork2.Action;  
      4. import com.opensymphony.xwork2.ActionInvocation;  
      5. import com.opensymphony.xwork2.interceptor.AbstractInterceptor;  
      6. import com.opensymphony.xwork2.ActionContext;  
      7. public class RightInterceptor extends AbstractInterceptor {  
      8.   
      9.     @Override  
      10.     public String intercept(ActionInvocation invocation) throws Exception {  
      11.         //System.out.println("拦截器开始验证");  
      12.         try  
      13.         {  
      14. actionContext = ActionContext.getContext();  
      15. <String,Object> session = actionContext.getSession();  
      16. user=session.get("usercode").toString();     
      17.             //当前用户session无效且访问的action不是登录action时,执行拦截,跳转  
      18. user==null || user.equals("")) && !invocation.getAction().getClass().getName().equals("登录action"))   
      19.             {  
      20.                 return Action.LOGIN;  
      21.             }  
      22.         }  
      23.         catch(Exception e)  
      24.         {  
      25.             e.printStackTrace();  
      26.             return Action.LOGIN;  
      27.         }  
      28.         //System.out.println("拦截器通过验证");  
      29.         return invocation.invoke();//执行访问的action  
      30.           
      31.   
      32.     }  
      33.   
      34. }



      拦截器由spring管理,只对action起作用,不能拦截jsp页面、图片等其他资源。拦截器截获用户对action的访问,如需要跳转,只需如action一样返回一个result,spring根据result的配置执行跳转。如无需跳转,可调用invocation.invoke();方法来执行用户请求的action。拦截器在action之前开始,在action完成后结束(如被拦截,action根本不执行)

      如不进行处理,过滤器和拦截器都会将正常的登录操作屏蔽,因此过滤器中需要判断用户访问的url是否为登录操作或登录页面,拦截器中需要判断用户访问的action是否登录action。



      ------------------=================================================================================

      Struts2项目通过使用Struts的if标签进行了session判断,使得未登录的用户不能看到页面,但是这 种现仅仅在view层进行,如果未登录用户直接在地址栏输入登录用户才能访问的地址,那么相应的action还是会执行,仅仅是不让用户看到罢了。这样显然是不好的,所以研究了一下Struts2的权限验证。

      权限最核心的是业务逻辑,具体用什么技术来实现就简单得多。 
      通常:用户与角色建立多对多关系,角色与业务模块构成多对多关系,权限管理在后者关系中。 
      对权限的拦截,如果系统请求量大,可以用Struts2拦截器来做,请求量小可以放在filter中。但一般单级拦截还不够,要做到更细粒度的权限控制,还需要多级拦截。

          不大理解filter(过滤器)和interceptor(拦截器)的区别,遂google之。博文中有介绍:

      1、拦截器是基于java的反射机制的,而过滤器是基于函数回调 。 
      2、过滤器依赖与servlet容器,而拦截器不依赖与servlet容器 。 
      3、拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求 起作用 。 
      4、拦截器可以访问action上下文、值栈里的对象,而过滤器不能 。 
      5、在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容 器初始化时被调用一次 。

          为了学习决定把两种实现方式都试一下,然后再决定使用哪个。

      权限验证的Filter实现:

      web.xml代码片段

        


        1. <!-- authority filter 最好加在Struts2的Filter前面-->  
        2. <filter>  
        3. <filter-name>SessionInvalidate</filter-name>  
        4. <filter-class>filter.SessionCheckFilter</filter-class>  
        5. <init-param>  
        6. <param-name>checkSessionKey</param-name>  
        7. <param-value>loginName</param-value>  
        8. </init-param>  
        9. <init-param>  
        10. <param-name>redirectURL</param-name>  
        11. <param-value>/entpLogin.jsp</param-value>  
        12. </init-param>  
        13. <init-param>  
        14. <param-name>notCheckURLList</param-name>  
        15. <param-value>/entpLogin.jsp,/rois/loginEntp.action,/entpRegister.jsp,/test.jsp,/rois/registerEntp.action</param-value>  
        16. </init-param>  
        17. </filter>  
        18. <!--过滤/rois命名空间下所有action  -->  
        19. <filter-mapping>  
        20. <filter-name>SessionInvalidate</filter-name>  
        21. <url-pattern>/rois/*</url-pattern>  
        22. </filter-mapping>  
        23. <!--过滤/jsp文件夹下所有jsp  -->  
        24. <filter-mapping>  
        25. <filter-name>SessionInvalidate</filter-name>  
        26. <url-pattern>/jsp/*</url-pattern>  
        27. </filter-mapping>



        SessionCheckFilter.java代码



        1. package filter;  
        2. import java.io.IOException;  
        3. import java.util.HashSet;  
        4. import java.util.Set;  
        5. import javax.servlet.Filter;  
        6. import javax.servlet.FilterChain;  
        7. import javax.servlet.FilterConfig;  
        8. import javax.servlet.ServletException;  
        9. import javax.servlet.ServletRequest;  
        10. import javax.servlet.ServletResponse;  
        11. import javax.servlet.http.HttpServletRequest;  
        12. import javax.servlet.http.HttpServletResponse;  
        13. import javax.servlet.http.HttpSession;  
        14. /**
        15.  * 用于检测用户是否登陆的过滤器,如果未登录,则重定向到指的登录页面 配置参数 checkSessionKey 需检查的在 Session 中保存的关键字
        16.  * redirectURL 如果用户未登录,则重定向到指定的页面,URL不包括 ContextPath notCheckURLList
        17.  * 不做检查的URL列表,以分号分开,并且 URL 中不包括 ContextPath
        18.  */  
        19. public class SessionCheckFilter implements Filter {  
        20. protected FilterConfig filterConfig = null;  
        21. private String redirectURL = null;  
        22. private Set<String> notCheckURLList = new HashSet<String>();  
        23. private String sessionKey = null;  
        24. @Override  
        25. public void destroy() {  
        26.     notCheckURLList.clear();  
        27.   }  
        28. @Override  
        29. public void doFilter(ServletRequest servletRequest,  
        30.       ServletResponse servletResponse, FilterChain filterChain)  
        31. throws IOException, ServletException {  
        32.     HttpServletRequest request = (HttpServletRequest) servletRequest;  
        33.     HttpServletResponse response = (HttpServletResponse) servletResponse;  
        34.     HttpSession session = request.getSession();  
        35. if (sessionKey == null) {  
        36.       filterChain.doFilter(request, response);  
        37. return;  
        38.     }  
        39. if ((!checkRequestURIIntNotFilterList(request))  
        40. null) {  
        41.       response.sendRedirect(request.getContextPath() + redirectURL);  
        42. return;  
        43.     }  
        44.     filterChain.doFilter(servletRequest, servletResponse);  
        45.   }  
        46. private boolean checkRequestURIIntNotFilterList(HttpServletRequest request) {  
        47.     String uri = request.getServletPath()  
        48. null ? "" : request.getPathInfo());  
        49.     String temp = request.getRequestURI();  
        50. 1);  
        51. // System.out.println("是否包括:"+uri+";"+notCheckURLList+"=="+notCheckURLList.contains(uri));  
        52. return notCheckURLList.contains(uri);  
        53.   }  
        54. @Override  
        55. public void init(FilterConfig filterConfig) throws ServletException {  
        56. this.filterConfig = filterConfig;  
        57. "redirectURL");  
        58. "checkSessionKey");  
        59.     String notCheckURLListStr = filterConfig  
        60. "notCheckURLList");  
        61. if (notCheckURLListStr != null) {  
        62.       System.out.println(notCheckURLListStr);  
        63. ",");  
        64. for (int i = 0; i < params.length; i++) {  
        65.         notCheckURLList.add(params[i].trim());  
        66.       }  
        67.     }  
        68.   }  
        69. }


        权限验证的Interceptor实现:

           使用Interceptor不需要更改web.xml,只需要对struts.xml进行配置

        struts.xml片段



        1. <!-- 用户拦截器定义在该元素下 -->  
        2. <interceptors>  
        3. <!-- 定义了一个名为authority的拦截器 -->  
        4. <interceptor name="authenticationInterceptor" class="interceptor.AuthInterceptor" />  
        5. <interceptor-stack name="defualtSecurityStackWithAuthentication">  
        6. <interceptor-ref name="defaultStack" />  
        7. <interceptor-ref name="authenticationInterceptor" />  
        8. </interceptor-stack>  
        9. </interceptors>  
        10. <default-interceptor-ref name="defualtSecurityStackWithAuthentication" />  
        11. <!-- 全局Result -->  
        12. <global-results>  
        13. <result name="error">/error.jsp</result>  
        14. <result name="login">/Login.jsp</result>  
        15. </global-results>  
        16. <action name="login" class="action.LoginAction">  
        17. <param name="withoutAuthentication">true</param>  
        18. <result name="success">/WEB-INF/jsp/welcome.jsp</result>  
        19. <result name="input">/Login.jsp</result>  
        20. </action>  
        21. <action name="viewBook" class="action.ViewBookAction">  
        22. <result name="sucess">/WEB-INF/viewBook.jsp</result>  
        23. </action>


        AuthInterceptor.java代码


          1. package interceptor;  
          2. import java.util.Map;  
          3. import com.opensymphony.xwork2.Action;  
          4. import com.opensymphony.xwork2.ActionContext;  
          5. import com.opensymphony.xwork2.ActionInvocation;  
          6. import com.opensymphony.xwork2.interceptor.AbstractInterceptor;  
          7. public class AuthInterceptor extends AbstractInterceptor {  
          8. private static final long serialVersionUID = -5114658085937727056L;  
          9. private String sessionKey="loginName";  
          10. private String parmKey="withoutAuthentication";  
          11. private boolean excluded;  
          12. @Override  
          13. public String intercept(ActionInvocation invocation) throws Exception {  
          14.       
          15.     ActionContext ac=invocation.getInvocationContext();  
          16.     Map<?, ?> session =ac.getSession();  
          17.     String parm=(String) ac.getParameters().get(parmKey);  
          18.       
          19. if(parm!=null){  
          20. "TRUE");  
          21.     }  
          22.       
          23.     String user=(String)session.get(sessionKey);  
          24. if(excluded || user!=null){  
          25. return invocation.invoke();  
          26.     }  
          27. "tip", "您还没有登录!");  
          28. //直接返回 login 的逻辑视图    
          29. return Action.LOGIN;   
          30.   }  
          31. }

           

          使用自定义的default-interceptor的话有需要注意几点:

          1.一定要引用一下Sturts2自带defaultStack。否则会用不了Struts2自带的拦截器。

          2.一旦在某个包下定义了上面的默认拦截器栈,在该包下的所有 Action 都会自动增加权限检查功能。所以有可能会出现永远登录不了的情况。

          解决方案:

          1.像上面的代码一样,在action里面增加一个参数表明不需要验证,然后在interceptor实现类里面检查是否不需要验证

          2.将那些不需要使用权限控制的 Action 定义在另一个包中,这个新的包中依然使用 Struts 2 原有的默认拦截器栈,将不会有权限控制功能。

          3.Interceptor是针对action的拦截,如果知道jsp地址的话在URL栏直接输入JSP的地址,那么权限验证是没有效果滴!

          解决方案:把所有page代码(jsp)放到WEB-INF下面,这个目录下的东西是“看不见”的