在Tapestry+Spring+Hibernate的框架中,安全控制可以直接采用Spring的拦截机制实现整个系统的安全,这一机制主要在页面层调用服务层方法时才会起作用, 为了实现页面级的安全控制,如用户点某个链接,服务端马上就可以在页面层实现拦截,用以解决类似如下的问题:
用户点击[新增定单]—>定单添加页面—>[定单提交],假如用户没有新增定单的权限,因为点击[新增定单]没有调用服务层方法,所以第一时间没有被拦住,而只有在[定单提交]调用新增定单的服务层方法时才会被拦下来,影响用户的体验。
实现中,主要要在你想拦截的方法声明前配置一个annotation,不想拦截的可以不配置,本实现可以重用已配置好的针对服务层拦截的权限数据。代码在Tapesty4.0上测试通过,以下是核心代码。
//以下为页面基类
package com.demo.tapestry;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.List;
import org.apache.hivemind.ApplicationRuntimeException;
import org.apache.tapestry.IComponent;
import org.apache.tapestry.IRender;
import org.apache.tapestry.binding.ListenerMethodBinding;
import org.apache.tapestry.event.PageEvent;
import org.apache.tapestry.event.PageValidateListener;
import org.apache.tapestry.form.AbstractFormComponent;
import org.apache.tapestry.form.Form;
import org.apache.tapestry.services.ServiceConstants;
import com.demo.annotation.Security;
/**
*
* 功能描述:带权限验证的页面基类
*
* @author iroyce
* Created on d2007-1-20
*/
public abstract class DemoProtectedBasePage extends DemoBasePage implements
PageValidateListener {
/**
* 页面校验方法
*/
public void pageValidate(PageEvent event) {
DemoVisit visit = (DemoVisit) getDemoVisit();
//=====================以下为页面层权限校验==================================================
String securityAnnotation = getMethodAnnotation();
log.info("securityAnnotation=" + securityAnnotation);
//以下是权限校验及相关处理....
//if ( !checkPermission(securityAnnotation, permission) ) 页面相关跳转;
}
/**
*方法用途和描述:得到页面类中方法所绑定的安全数据
*@return方法所绑定的安全数据字符串,如com.demo.service.IMemberManager.addMemberMsg
*/
private String getMethodAnnotation(){
String componentName = this.getRequestCycle().getParameter(ServiceConstants.COMPONENT);
if(componentName==null || "".equals(componentName))
return null;
String methodName = null;
if(componentName!=null && this.getRequest().getAttribute("isChecked")==null){
try{
ListenerMethodBinding lmb = (ListenerMethodBinding)this.getComponent(componentName).getBinding("listener");
if(lmb!=null)
methodName = this.getMethodName(lmb.toString());
else
methodName = getMethodName(getBindingString(componentName));
this.getRequest().setAttribute("isChecked", new StringBuffer("T"));
}catch(ApplicationRuntimeException e){
log.error(":::::::ApplicationRuntimeException from class#" + this.getClass() + " method#pageValidate :::::::");
}
}
if(methodName!=null){
Method[] ms = this.getClass().getMethods();
Method mm = null;
for (int i=0; i
mm = ms[i];
break;
}
}
Security security = mm.getAnnotation(Security.class);
//得到方法相应的配置数据
if(security!=null)
return security.methodName();
}
return null;
}
/**
* 方法用途和描述: 得到绑定的监听类描述串,其中含有监听方法名部份,T4中并未把监听方法名暴露给编程人员访问
* @author iroyce
*/
private String getBindingString(String formid){
if (formid==null) return null;
IComponent ic = this.getComponent(formid);
if(!(ic instanceof Form)) return null;
Form ff = (Form)ic;
IRender[] ir = ff.getBody();
if(ir==null) return null;
ListenerMethodBinding lmb = null;
for (int i=ir.length-1; i>=0; i--){
if (ir[i] instanceof AbstractFormComponent ){
AbstractFormComponent afc = (AbstractFormComponent)ir[i];
lmb = (ListenerMethodBinding)afc.getBinding("listener");
if (lmb!=null) break;
}
}
//
if (lmb==null) return ic.getBindings().toString();
return lmb.toString();
}
/**
* 方法用途和描述: 得到监听方法名
* @author iroyce
*/
private String getMethodName(String methodSource){
if(methodSource==null) return null;
String methodName = methodSource.toString();
int start = methodName.indexOf("methodName=");
if(start==-1) return null;
start += 11;
methodName = methodName.substring(start);
methodName = methodName.substring(0, methodName.indexOf(","));
//methodName = this.getPage().getSpecification().getComponentClassName() + "." + methodName;
log.info("methodName=" + methodName);
return methodName;
}
/**
* 方法用途和描述: 判断当前要执行前台的权限是否可以执行
* 方法的实现逻辑描述:将当前要执行前台的权限和缓存里保存当前前台角色所拥有的权限一一比较,如果有匹配的就返回true,否则返回false
* @param methodName 当前要执行前台的权限
* @return 返回结果true--用户具有该权限 false--用户不具有该权限
* @exception IOException 异常信息描述(如果此方法会throws 异常)
* @author iroyce
*/
private boolean checkPermission(String methodName, List permission){
return true;
}
}
//以下为自定义的Annotation