在本系列的上一篇中我们介绍了一个基于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+Spring2+iBatis2+MySQL5,演示了一个用户表的增、删、改、查。 想完整学习Struts2+Spring+iBatis的同仁,可以在这个例子中学习或模仿最基本也是最核心的技术要点。
用struts2+spring+ibatis实现了 增删查改翻页功能,使用的数据库是mysql, web服务器是tomcat
Struts 1+Struts 2+Spring+Hibernate+iBATIS知识
flex+spring+struts2+ibatis 整合的eclipse工程,可以导入eclipse环境下直接使用,因为加入开发的jar大于了上传的最大限制,只能把jar另外打包上传,下载可以从我上传资源的lib1,lib2下载,这个工程的搭建花费了我两...
目标:WEB项目-集成Flex3+BlazeDS3.2+Spring2.5.6+iBatis2.3.4+Struts2.1.8,重在整合Spring与Struts2,并采用托管的方式,即Struts2 action托管于Spring 优点:这是一种保守的混合开发模式,既充分利用了原有的...
自己写的一个maven管理的spring+struts2+ibatis+velocity实例。项目已经打包好了,直接导入部署即可。
struts2+ibatis+spring+Hessian 整合项目 web项目整合,服务端用hessian协议远程调用服务端的方法,hessian是用spring代理整合,struts2+ibatis+spring的整合项目,用作学习和开发基础平台构建很有用处,工程导入...
基于spring+struts+ibatis的java web框架
web service 博文链接:https://wuxufeng8080.iteye.com/blog/102008
此资源是一个完成的Web Project,采用ssi框架(struts+spring+ibatis),mysql数据库
3.如果您不是采用MyEclipse5.1开发,可能无法部署项目,或者提示什么一个文件上锁什么的,请不要使用导入项目,您可以自己建立一个 web工程,名字叫做bmsh(一定要bmsh,因为我页面中的图片和js引用的时候写了绝对...
学习maven笔记,尚不能实现自动发布,parent工程package之后,把module项目的war手工发布到tomcat的webapp下。
spring iBATIS struts1集成例子,详细源码
Struts+Spring+ibatis开发的Jpetstore宠物商店的开源程序,在SourceForce上下载的,学JAVA WEB开发的人研究的热门开源程序。有需要的同学分享吧!这里提供的是一个下载地址,因为有点大,所以就提供了一个地址,大家...
这是本人从实际项目开发中总结出来的,具有很强的实用性,有关Struts,Spring,Ibatis,web 四个文件的详细配置。值得初学者,以及想实际搭建框架者学习。
ibatis_struts2_spring_介绍
很详细,已经搭通,功能有注册和登陆,简单的实例,集成了spring3.2.6和struts2.3.15以及ibatis2.3.4
这个是自己在刚开始接触java时写的一个Spring+Struts+ibatis结构的web工程,实现了对一张表的增删查改