`

Struts 2 的拦截器(三)

阅读更多

 

六、 拦截器示例 : 实现权限控制

权限检查,当浏览者需要请求执行某个操作时,应用首先需要检查浏览者是否登录,以及是否有足够的权限来执行该操作

 

6.1 实现拦截器

在这里会实现所有例子,后面章节在一一解释

 

   本示例应用要求用户登录,且必须为指定用户名才可以查看系统中某个视图资源: 否则,系统直接转入登录页面。

   对于上述的需求,可以在每个 Action 的执行实际处理逻辑之前,先执行权限检查逻辑,为了代码复用,可以使用拦截器。

 

   个人认为判断 session 用 过滤器比较好 如下:

web.xml

  <filter>
  	<filter-name>SessionInvalidate</filter-name>
  	<filter-class>com.sysoft.baselib.web.SessionCheckFilter</filter-class>
  	<init-param>
  		<param-name>checkSessionKey</param-name>
  		<param-value>APP_SESSION_TOKEN</param-value>
  	</init-param>
  	<init-param>
  		<param-name>redirectURL</param-name>
  		<param-value>/sessionInvalidate.jsp</param-value>
  	</init-param>
  	<init-param>
  		<param-name>notCheckURLList</param-name>
  		<param-value>/login.jsp,/logon.do,/logout.jsp,/Index2/index.jsp,/sessionInvalidate.jsp,/Index2/maintop.jsp,/html.jsp</param-value>
  	</init-param>
  </filter>
  <filter-mapping>
  	<filter-name>SessionInvalidate</filter-name>
  	<url-pattern>*.do</url-pattern>  	
  </filter-mapping>
 <filter-mapping>
  	<filter-name>SessionInvalidate</filter-name>
  	<url-pattern>*.jsp</url-pattern>  	
  </filter-mapping>

 SessionCheckFilter.java

package com.sysoft.baselib.web;

import java.io.IOException;
import java.util.HashSet;
import java.util.Set;

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;
/**      
* 用于检测用户是否登陆的过滤器,如果未登录,则重定向到指的登录页面       
* 配置参数            
* checkSessionKey 需检查的在 Session 中保存的关键字      
* redirectURL 如果用户未登录,则重定向到指定的页面,URL不包括 ContextPath       
* notCheckURLList 不做检查的URL列表,以分号分开,并且 URL 中不包括 ContextPath  
*/    
public class SessionCheckFilter implements Filter {
	protected FilterConfig filterConfig = null;
	private String redirectURL = null;
	private Set notCheckURLList = new HashSet();
	private String sessionKey = null;

	public void doFilter(ServletRequest servletRequest,
			ServletResponse servletResponse, FilterChain filterChain)
			throws IOException, ServletException {
		HttpServletRequest request = (HttpServletRequest) servletRequest;
		HttpServletResponse response = (HttpServletResponse) servletResponse;

		HttpSession session = request.getSession();
		if (sessionKey == null) {
			filterChain.doFilter(request, response);
			return;
		}
		if ((!checkRequestURIIntNotFilterList(request))
				&& session.getAttribute(sessionKey) == null) {
			response.sendRedirect(request.getContextPath() +redirectURL);
			return;
		}
		filterChain.doFilter(servletRequest, servletResponse);
	}

	public void destroy() {
		notCheckURLList.clear();
	}

	private boolean checkRequestURIIntNotFilterList(HttpServletRequest request) {
		String uri = request.getServletPath()
				+ (request.getPathInfo() == null ? "" : request.getPathInfo());
		String temp = request.getRequestURI();
		temp= temp.substring(request.getContextPath().length()+1);
		//System.out.println("是否包括:"+uri+";"+notCheckURLList+"=="+notCheckURLList.contains(uri));
		return notCheckURLList.contains(uri);
		
	}

	public void init(FilterConfig filterConfig) throws ServletException {
		this.filterConfig = filterConfig;
		redirectURL = filterConfig.getInitParameter("redirectURL");
		sessionKey = filterConfig.getInitParameter("checkSessionKey");

		String notCheckURLListStr = filterConfig
				.getInitParameter("notCheckURLList");
		if(notCheckURLListStr != null){
			System.out.println(notCheckURLListStr);
			String[] params = notCheckURLListStr.split(",");
			for(int i=0;i<params.length;i++){
				notCheckURLList.add(params[i].trim());
			}
		}
		
	}
}
 

 

    检查用户是否登录,通常都是通过跟踪用户的 HTTPSession 来完成的,通过 ActionContext 即可访问到 Session 中的属性,拦截器的 intercepte(ActionInvocation invocation) invocation 参数可以访问到请求相关的 ActionContext 实例

 

权限查看拦截器的例子

 

AuthorityInterceptor.java

package js.authority;

import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.Action;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
import java.util.*;

public class AuthorityInterceptor extends AbstractInterceptor {
    public String intercept(ActionInvocation invocation) throws Exception {
        ActionContext ctx = invocation.getInvocationContext();
        Map session = ctx.getSession();
        String user = (String) session.get("user");

        if (user != null && user.equals("crazyit")) {
            return invocation.invoke();
        }
        ctx.put("tip", "您还没有登录,请输入crazyit,leegang登录系统");

//直接返回 login 的逻辑视图
        return Action.LOGIN;
    }
}

 通过 ActionInvocation 参数取得 session 实例,然后取出 user ,来判断用户是否登录,从而判断是否需要转入登录页面

 

LoginAction.java

package js.authority;

import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ActionContext;
import java.util.*;

public class LoginAction extends ActionSupport {
    private String username;

    private String password;

    public void setUsername(String username) {
        this.username = username;
    }

    public String getUsername() {
        return username;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getPassword() {
        return password;
    }

    public String execute() throws Exception {
        Thread.sleep(1500);
        if (getUsername().equals("crazyit") && getPassword().equals("leegang")) {
            ActionContext ctx = ActionContext.getContext();
            Map session = ctx.getSession();
            session.put("user", getUsername());
            return SUCCESS;
        } else {
            return ERROR;
        }
    }

}
 

struts.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.2.dtd">
<struts>
	<constant name="struts.custom.i18n.resources"
		value="messageResource"/>
	<constant name="struts.i18n.encoding" value="GBK"/>	
	<package name="js.authority"  extends="struts-default" namespace="/authority">
		<!-- 用户拦截器定义在该元素下 -->
		<interceptors>
			<!-- 定义了一个名为authority的拦截器 -->
			<interceptor name="authority" class="js.authority.AuthorityInterceptor"/>
		</interceptors>

		<!-- 定义全局Result -->
		<global-results>
			<!-- 当返回login视图名时,转入/login.jsp页面 -->
			<result name="login">/authority/login.jsp</result>
		</global-results>

		<action name="login" class="js.authority.LoginAction">
			<result name="error">/authority/error.jsp</result>
			<result name="success">/authority/welcome.jsp</result>
		</action>
		<!-- 定义一个名为viewBook的Action,其实现类为ActionSupport -->
		<action name="viewBook">
			<!-- 返回success视图名时,转入/WEB-INF/jsp/viewBook.jsp页面 -->
			<result>/WEB-INF/jsp/viewBook.jsp</result>
			<!-- 拦截器一般配置在result元素之后! -->
			<interceptor-ref name="defaultStack"/>
			<!-- 应用自定义拦截器 -->
			<interceptor-ref name="authority"/>
		</action>
		<action name="">
			<result>.</result>
		</action>
	</package>
</struts>
 

/authority/login.jsp

<%@ page contentType="text/html; charset=GBK" language="java" errorPage="" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"	"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<%@taglib prefix="s" uri="/struts-tags"%>
<html>
<head>
	<title>登录页面</title>
</head>
<body>
<div style="color:red" align="center">${requestScope.tip}</div>
<form action="login.action" method="post">
<table align="center">
	<caption><h3>用户登录</h3></caption>
	<tr>
	<td>用户名:<input type="text" name="username"/></td>
	</tr>
	<tr>
		<td>密码:<input type="text" name="password"/></td>
	</tr>
	<tr align="center">
		<td><input type="submit" value="登录"/>
			<input type="reset" value="重填" /></td>
	</tr>
</table>
</form>
<div align="center"><a href="viewBook.action">
	查看作者李刚出版的图书</a>
</div>
</body>
</html>
 

/authority/welcome.jsp

<%@ page contentType="text/html; charset=GBK" language="java" errorPage="" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"	"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
	<title>成功页面</title>
</head>
<body>
	您已经登录!<br />
	<a href="viewBook.action">查看作者李刚出版的图书</a>
</body>
</html>
 

/authority/error.jsp

<%@ page contentType="text/html; charset=GBK" language="java" errorPage="" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"	"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
	<title>错误页面</title>
</head>
<body>
您不能登录!<br />
	<a href="viewBook.action">查看作者李刚出版的图书</a>
</body>
</html>
 

/WEB-INF/jsp/viewBook.jsp

<%@ page contentType="text/html; charset=GBK" language="java" errorPage="" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"	"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
	<title>作者李刚已经出版的图书:</title>
</head>
<body>
	<h3>作者李刚已经出版的图书:</h3>
	疯狂Java讲义<br />
	轻量级Java EE企业实战<br />
	疯狂Ajax讲义<br />
</body>
</html>
 <s:a href="" onclick="newWin('authority/login.jsp');" cssStyle="cursor: hand;">authority/login.jsp</s:a>

 

 

6.2  配置权限控制拦截器

以下代码全部基于 6.1

 

   6.1struts.xml 中的 viewBook Action , 没有指定 class 属性,默认使用 ActionSupport 类,配置该 Action 时,只指定了一个结果映射,指定系统返回 success 字符串时,系统将转入 /WEB-INF/jsp/viewBook.jsp ,但未配置 login 视图名对应的 jsp

 

   考虑到这个拦截器的重复使用,可能多个 Action 都需要跳转到 login 逻辑视图,故将 login 的结果映射定义成一个全局结果映射

<!-- 定义全局Result -->
<global-results>
	<!-- 当返回login视图名时,转入/login.jsp页面 -->
	<result name="login">/authority/login.jsp</result>
</global-results>
 

为了简化 struts.xml 文件配置,避免在每个 Action 中重复配置该拦截器,可以将该拦截器配置成一个默认拦截器栈(这个默认拦截器栈应该包括 default-stack 拦截器栈和权限检查拦截器)

<!-- 用户拦截器定义在该元素下 -->
		<interceptors>
			<!-- 定义了一个名为authority的拦截器 -->
			<interceptor name="authority" class="js.authority.AuthorityInterceptor"/>
			<interceptor-stack name="mydefault">
				<interceptor-ref name="defaultStack"/>
				<interceptor-ref name="authority"/>
			</interceptor-stack>
		</interceptors>
		<default-interceptor-ref name="mydefault"/>

不过  6.1 的例子 不能使用默认拦截器,因为 login Action 不能被拦截,否则将永远不能登录


解决方法: 一旦在某个包下定义了上面的默认拦截器栈,在该包下的所有 Action 都会自动增加权限检查功能,对于那些不需要使用权限控制的 Action ,将它们定义在另一个包中,这个新的包中依然使用 Struts 2 原有的默认拦截器栈,将不会有权限控制功能。

 

 

 

 

 

 

分享到:
评论
发表评论

文章已被作者锁定,不允许评论。

相关推荐

Global site tag (gtag.js) - Google Analytics