`

基于Struts2+Spring+iBatis的web应用最佳实践系列之三(访问控制篇下)

阅读更多

在本系列的上一篇中我们介绍了一个基于cookie的访问控制方法,细心的读者一定会发现,这种方法的实现还是最终基于Struts2的拦截器机制,也就是说它只能保护web应用中的action资源,对于Struts2的应用来说,除了aciton外,一定会有不少的jsp页面。那么,我们又该如何实现对于jsp页面的访问控制呢?其实对于这样的问题,笔者在网络看到过已经不止一次了,下面我们就来介绍一种对于jsp页面的访问控制方法。

 

首先,笔者要祭出WEB-INF这个目录(呵呵,先不要砸我),这个目录是在servlet规范中定义的,每个web应用都会有,并且用户是访问不到的,难么很自然的一个想法就是把所有的jsp页面都放在这个目录下,而所有的请求都通过action来完成。但是这样也同时引入一个问题,即我们需要为每个页面都写一个对应的action,但是很多情况下,并不需要action中有任何逻辑,仅仅只是做一简单的跳转而已。对于这样的情况,如果我们为每个jsp页面都写一个对应的action就会显得很繁琐。

 

笔者在介绍一种可以解决这个问题的方法,首先,我们定义一个dispatcherAction,这个action什么也不做,只是为了跳转而存在,但是继承一下actionSupport。就象这样

 

public class DispatcherAction extends ActionSupport {}

 

 然而在struts.xml中我们却可以这样配

 

	<package name="demo" namespace="/demo" extends="default">
		<action name="*" class="com.meidusa.demo.web.action.DispatcherAction ">
			<result name="success">/WEB-INF/jsp/demo/{1}.jsp</result>
		</action>
	</package>	

 

 初看上去这种风格的配置有点怪异,不过一旦发现它的强大之处你就会喜欢上它。在这里,action name我们并没有指定一个具体的名字,而是用了一个'*'号来表示,'*'号是一个通配符,当没有全值匹配到一个action name的时候,它可以匹配任何名字,而result页面中的{1}则会被替换成'*'所代表的值。这样一来,我们可以只写一个DispatcherAction(甚至可以不写),实现对任意jsp页面的跳转。假设我们的域名是www.meidusa.com,request请求URL是www.meidusa.com/demo/login.aciton,它会自动跳转到/WEB-INF/jsp/demo/login.jsp页面。这种RESTful风格的action Mapping在Struts2的源码里作者也直言不讳的指出是受到了Ruby on Rails的启发,有兴趣的朋友可以继续深入研究一下Restful2ActionMapper这个类,说不定还可以挖掘到更多的宝贝,这里则不再赘述。

 

好了,现在我们有了DispatcherAction这个类轻松实现了对jsp的页面的跳转,不过并没有实现任何的访问控制功能,下面我们结合上一篇提到的cookie访问机制,改造一下DispatcherAction这个类。

  

public class DispatcherAction extends ActionSupport implements	ClientCookieAware<Cookie>{

	private Cookie cookie;
	
	public Cookie getCookie() {
		return cookie;
	}
	public void setClientCookie(Cookie cookie) {
		this.cookie = cookie;

	}

}

 

同时我们再写一个DispatcherCookieNotCareAction类

 

public class DispatcherCookieNotCareAction extends ActionSupport implements  ClientCookieNotCare{

}

 

这样,当我们需要保护某些jsp页面,即只有登录之后才能访问的页面使用DispatcherAction这个类来跳转,而对于不需要保护的页面使用DispatcherCookieNotCareAction类。不过要记得把我们的cookieInterceptor放到拦截器堆栈中。

 

现在,用我们的DispatcherAction类再结合我们的cookie访问机制又实现了对除aciton之外的jsp页面的控制。不过看到这里,有些朋友可能又要问了,使用'*'通配符那不是匹配了所有的jsp页面吗?如果某些jsp页面仅仅是用作action的返回结果,并不想直接暴露给用户访问该怎么办呢?在解决这个问题前,我们先来研究一下Struts2中的staticParams拦截器。

 

public class StaticParametersInterceptor extends AbstractInterceptor {

    private boolean parse;
    
    private static final Log LOG = LogFactory.getLog(StaticParametersInterceptor.class);

    public void setParse(String value) {
        this.parse = Boolean.valueOf(value).booleanValue();
    }

    public String intercept(ActionInvocation invocation) throws Exception {
        ActionConfig config = invocation.getProxy().getConfig();
        Object action = invocation.getAction();

        final Map parameters = config.getParams();

        if (LOG.isDebugEnabled()) {
            LOG.debug("Setting static parameters " + parameters);
        }

        // for actions marked as Parameterizable, pass the static parameters directly
        if (action instanceof Parameterizable) {
            ((Parameterizable) action).setParams(parameters);
        }

        if (parameters != null) {
            final ValueStack stack = ActionContext.getContext().getValueStack();

            for (Iterator iterator = parameters.entrySet().iterator();
                 iterator.hasNext();) {
                Map.Entry entry = (Map.Entry) iterator.next();
                stack.setValue(entry.getKey().toString(), entry.getValue());
                Object val = entry.getValue();
                if (parse && val instanceof String) {
                    val = TextParseUtil.translateVariables((String) val, stack);
                }
                stack.setValue(entry.getKey().toString(), val);
            }
        }
        return invocation.invoke();
    }
}

 

这个拦截器已经在默认的拦截器堆栈中,它可以把action配置中的静态属性以map的形式注入到action中,当然前题是这个aciton实现Parameterizable的接口

  

public interface Parameterizable {

    public void addParam(String name, Object value);

    void setParams(Map<String, Object> params);

    Map getParams();
}

 

在这里,我们主要定义两个属性,一个includes,一个excludes。includes代表只允许访问的jsp页面,excludes代表剔除不允许访问的页面之外其他页面都允许访问,也就是通常说的黑白名单控制法。这两个属性可以都设置,也可以只设置一个,也可以不设置。我们来看一个例子,假设我们有一个profile.jsp放在了/WEB-INF/jsp/demo目录下。当用户登录后跳转到这个jsp页面上,显然这个页面只有通过login action执行后跳转而不允许直接访问。我们可以在action的配置中设置excludes属性<param name="excludes">profile</param>

 

	<package name="demo" namespace="/demo" extends="default">
		<action name="*" class="com.meidusa.demo.web.action.DispatcherAction ">
			<param name="excludes">profile</param>
			<result name="success">/WEB-INF/jsp/demo/{1}.jsp</result>
			<result name="none">/WEB-INF/jsp/demo/error.jsp</result>
		</action>
	</package>

 

 

现在action已经配置好了,问题是要如何做到对配置好的黑白名单进行控制呢?答案仍旧是用Struts2的拦截器来实现。不知道大家在前面两个例子中有没有发现这样一个有趣的现象,每一个拦截器经常都会有一个配对的由action实现的借口,比如我们的ClientCookieInterceptor拦截器和ClientCookieAware接口(当然了,还有ClientCookieNotCare);StaticParametersInterceptor拦截器和Parameterizable接口。那在我们讨论具体如何实现这个拦截器之前不妨先看一下这个接口应该怎么实现。 

 

public interface Dispatchable {

	public String getIncludes();
	public String getExcludes();
}

 

 其实很简单,呵呵,这个Dispatchable接口只有两个方法getIncludes()和getExcludes()。也就是说这个拦截器在拦截的时候从被拦截的aciton中读取用StaticParametersInterceptor注入的includes和excludes属性。但是要注意一点,在配置拦截器堆栈的时候需要把StaticParametersInterceptor放在我们的DispatcherInterceptor拦截器之前,因为我们的拦截器依赖于它。

 

最后来看一下我们的DispatcherInterceptor拦截器。通过从aciton读取的includes和excludes属性判断这个aciton是否允许被访问。

 

public class DispatcherInterceptor extends AbstractInterceptor {

	@Override
	public String intercept(ActionInvocation invocation) throws Exception {
		if (invocation.getAction() instanceof Dispatchable){
			Dispatchable action = (Dispatchable)invocation.getAction();
			ActionContext context = ActionContext.getContext();
			
			//判断这个aciton是否允许被访问
			boolean allow = apply(action.getExcludes(), action.getIncludes(), context.getName());
			if (!allow){
				return Action.NONE;
			}
		}
		return invocation.invoke();
	}

		//黑白名单控制规则
    public static boolean apply(Set excludes, Set includes, String action) {
    	if (((excludes.contains("*") && !includes.contains("*"))
                || excludes.contains(action))
                && !includes.contains(action)) {
            return false;
        }
        return includes.size() == 0 || includes.contains(action) || includes.contains("*");
    }

    public static boolean apply(String excludes, String includes, String action) {
    	Set includesSet = TextParseUtil.commaDelimitedStringToSet(includes == null? "" : includes);
    	Set excludesSet = TextParseUtil.commaDelimitedStringToSet(excludes == null? "" : excludes);
    	
    	return apply(excludesSet, includesSet, action);
    }
}

  

最后我们再来看一下最终修改后的DispatcherAction

 

public class DispatcherAction extends ActionSupport implements	ClientCookieAware<Cookie>, Dispatchable, Parameterizable{

	private Cookie cookie;
	private Map params;
	
	public String getIncludes() {
		return (String)params.get("includes");
	}
	public String getExcludes() {
		return (String)params.get("excludes");
	}
	public Cookie getCookie() {
		return cookie;
	}
	public void setClientCookie(Cookie cookie) {
		this.cookie = cookie;

	}
    public void addParam(String name, Object value){
    	this.params.put(name, value);
    }

    public void setParams(Map<String, Object> params){
    	this.params = params;
    }

    public Map getParams(){
    	return params;
    }

}

 

 最终修改后的DispatcherCookieNotCareAction

public class DispatcherCookieNotCareAction extends ActionSupport implements
ClientCookieNotCare, Dispatchable, Parameterizable {
	private Map params;
	
	public String getIncludes() {
		return (String)params.get("includes");
	}
	public String getExcludes() {
		return (String)params.get("excludes");
	}
    public void addParam(String name, Object value){
    	this.params.put(name, value);
    }

    public void setParams(Map<String, Object> params){
    	this.params = params;
    }

    public Map getParams(){
    	return params;
    }
}

 

至此,我们同样成功实现了对jsp页面的访问控制。

分享到:
评论

相关推荐

    struts2+spring+Ibatis框架包

    这个“struts2+spring+iBatis框架包”集成了这三个框架,使得开发者能够快速构建基于MVC(Model-View-Controller)模式的Web应用。 Struts2作为MVC框架,负责处理应用程序的控制逻辑。它通过Action类和配置文件定义...

    struts2+spring3+ibatis项目整合案例

    Struts2、Spring3和iBATIS是Java Web开发中常用的三大框架,它们各自负责不同的职责,协同工作可以构建出高效、松耦合的Web应用。在这个“struts2+spring3+ibatis项目整合案例”中,我们将深入探讨这三个框架如何...

    Struts2+Spring2+iBatis2整合的例子

    Struts2、Spring和iBatis是Java Web开发中三个非常重要的框架,它们分别负责表现层、业务层和数据访问层。将这三个框架整合在一起,可以实现MVC(Model-View-Controller)架构,提高应用的灵活性和可维护性。 **...

    struts2+spring2+ibatis

    Struts2、Spring和iBatis是Java Web开发中三个非常重要的开源框架,它们的集成应用可以构建出高效、灵活的后端系统。Struts2作为MVC(Model-View-Controller)架构的一部分,主要负责处理HTTP请求和展示视图;Spring...

    Struts2+Spring+Hibernate和Struts2+Spring+Ibatis

    Struts2+Spring+Hibernate和Struts2+Spring+Ibatis是两种常见的Java Web应用程序集成框架,它们分别基于ORM框架Hibernate和轻量级数据访问框架Ibatis。这两种框架结合Spring,旨在提供一个强大的、可扩展的、易于...

    struts2+spring+ibatis+mysql

    "Struts2+Spring+Ibatis+MySQL" 是一个经典的Java Web开发框架组合,用于构建高效、可扩展的企业级应用程序。这个组合集成了强大的MVC(Model-View-Controller)框架Struts2、依赖注入与面向切面编程的Spring框架、...

    Struts2+Spring2+iBatis2+MySQL的完整示例

    开发环境说明 ...本示例完整地结合Struts2+Spring2+iBatis2+MySQL5,演示了一个用户表的增、删、改、查。 想完整学习Struts2+Spring+iBatis的同仁,可以在这个例子中学习或模仿最基本也是最核心的技术要点。

    Struts2+Spring2.5+Ibatis完整增删改查Demo(含全部jar包)

    Struts2、Spring和iBatis是Java Web开发中经典的三大框架,它们分别负责MVC模式中的Action层、业务逻辑层和服务数据访问层。这个"Struts2+Spring2.5+iBatis完整增删改查Demo"提供了一个完整的集成示例,包括所有必要...

    spring+struts2+ibatis整合的jar包

    在Java Web开发中,Spring、Struts2和iBatis是三个非常重要的框架,它们各自在不同的层面上提供了强大的功能。Spring是一个全面的后端应用框架,提供了依赖注入(DI)、面向切面编程(AOP)、事务管理等功能;Struts...

    Struts2+spring+ibatis三大框架整合实例

    Struts2、Spring和iBatis是Java Web开发中常用的三大框架,它们分别负责MVC模式中的Action层、业务逻辑层和服务数据访问层。本文将详细介绍这三个框架如何整合,以及在实际项目中如何运用。 首先,Struts2作为表现...

    struts2+spring2+ibatis集成

    Struts2、Spring2 和 iBatis 是三个在Java Web开发中广泛应用的开源框架,它们分别负责MVC架构中的控制层、服务层和数据访问层。这个集成项目,"SSITest",是为了帮助初学者理解和实践这三大框架的协同工作。 **...

    struts2+spring+ibatis整合项目实例

    Struts2、Spring和iBatis是Java Web开发中常用的三个开源框架,它们各自负责不同的职责,协同工作可以构建出高效、松耦合的Web应用。这个整合项目实例旨在展示如何将这三个框架集成到一起,以实现更强大的功能。 1....

    struts2+spring+ibatis项目实例

    Struts2、Spring和iBatis是Java Web开发中经典的三大框架,它们组合起来可以构建出高效、可维护的企业级应用程序。在这个项目实例中,我们将深入探讨这三个框架如何协同工作,以及它们各自的核心功能。 首先,...

    struts2+spring+ibatis的小demo

    Struts2、Spring和iBatis是Java Web开发中经典的三大框架,它们组合起来可以构建出高效、可维护的企业级应用程序。在这个“struts2+spring+ibatis”的小demo中,我们将深入探讨这三个框架的核心功能以及它们如何协同...

    struts2 + spring + ibatis 整合例子

    Struts2、Spring和iBatis是Java Web开发中常用的三大框架,它们分别负责MVC模式中的Action层、业务逻辑层以及数据访问层。将这三个框架整合在一起,可以构建出高效、灵活且易于维护的Web应用程序。下面我们将详细...

    struts2+spring2+ibatis简单登录例子

    Struts2、Spring2和iBatis是Java Web开发中常用的三大框架,它们结合使用可以构建高效、可扩展的企业级应用程序。在这个简单的登录例子中,我们将深入探讨这三个框架如何协同工作来实现用户身份验证。 首先,Struts...

    spring3+struts2+ibatis

    在现代企业级Web应用开发中,Spring、Struts2和Ibatis是常见的三大组件,它们各自负责不同的职责,共同构建出高效、灵活的应用架构。Spring作为全能型的框架,提供依赖注入(DI)和面向切面编程(AOP)等功能;...

    struts2+spring+ibatis+oracle+分页搜索+上传附件实例

    Struts2、Spring、iBatis以及Oracle是Java Web开发中的四大核心组件,它们共同构建了一个强大且灵活的后端架构。在这个实例中,我们将会深入探讨这些技术如何协同工作,实现分页搜索功能和上传附件操作。 1. **...

    struts2+spring+mybatis+easyui的实现

    Struts2、Spring和MyBatis是Java Web开发中经典的三大框架,它们分别负责MVC模式中的控制层、业务层和服务层。EasyUI则是一个基于jQuery的UI组件库,用于快速构建美观且响应式的Web应用界面。下面我们将深入探讨这三...

    Struts2+Spring2.5+Ibatis2.3架构

    Struts2+Spring2.5+Ibatis2.3架构是一种经典的Java Web开发技术栈,广泛应用于企业级应用系统中。这个架构结合了Struts2的MVC框架、Spring的依赖注入(DI)和面向切面编程(AOP)以及Ibatis的持久层解决方案,为...

Global site tag (gtag.js) - Google Analytics