论坛首页 Java企业应用论坛

Annotation与Tapestry4.0页面拦截

浏览 5550 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2006-12-05  

<o:p> </o:p>

Tapestry+Spring+Hibernate的框架中,安全控制可以直接采用Spring的拦截机制实现整个系统的安全,这一机制主要在页面层调用服务层方法时才会起作用, 为了实现页面级的安全控制,如用户点某个链接,服务端马上就可以在页面层实现拦截,用以解决类似如下的问题:<o:p></o:p>

用户点击[新增定单]>定单添加页面—>[定单提交],假如用户没有新增定单的权限,因为点击[新增定单]没有调用服务层方法,所以第一时间没有被拦住,而只有在[定单提交]调用新增定单的服务层方法时才会被拦下来,影响用户的体验。<o:p></o:p>

实现中,主要要在你想拦截的方法声明前配置一个annotation,不想拦截的可以不配置,本实现可以重用已配置好的针对服务层拦截的权限数据。代码在Tapesty4.0上测试通过,以下是核心代码。<o:p></o:p>

//以下为页面基类

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<ms.length; i++){
              if (ms[i].getName().equals(methodName)){
                 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;
   }
  }
  //<form jwcid="@Form" success="listener:foo"/>等情况
  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;
 }
}

<o:p></o:p>

//以下为页面类中的一个监听方法
/**
*方法用途和描述:回复短消息
*服务层方法com.demo.service.IMemberManager.addMemberMsg与该监听
*方法绑定,访问该监听方法必须具有访问
*com.demo.service.IMemberManager.addMemberMsg的权限
*/
  @Security(methodName="com.demo.service.IMemberManager.addMemberMsg")
    public IPage answerMessage(String msgID) {
       //......
    }

//以下为自定义的Annotation

package com.demo.annotation;
 
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
 
/**
 * 功能描述: 页面类安全代码配置
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Security {
       String methodName();         
}
   发表时间:2006-12-20  
0 请登录后投票
   发表时间:2006-12-20  
你好,我用你的方法试了一下,但是好像不行,lmb = (ListenerMethodBinding)this.getComponent(componentName).getBindings().get("listener");获得不到内容。我的一个链接在form中的时候,获得的component是form对象,而form的linstener并没有触发,不知道你遇到这种问题没有。
0 请登录后投票
   发表时间:2006-12-21  
如果你提交表单时,URL带有该Form组件对应的名字(id)时,就能在服务端能获得该组件名字对应的监听方法名(服务端就是通过这个URL获取用户触发了哪个组件,T4运行时环境有配置信息来记录组件名与监听方法名的对应).

一句话就是:请求中的URL如果带有组件名(id)信息,就能在服务端获得对应的监听方法名.

不太清楚你所描述的情况...不知可不可以让我看看你的页面与页面类代码???
0 请登录后投票
   发表时间:2006-12-21  
我使用的是在html中<form jwcid="pageform@Form"> <input name="pageNum" type="text" class="inputGO" jwcid="pagenum"/>页&nbsp;&nbsp;<a jwcid="go">go</a></form>
配置文件:
<component id="pagenum" type="TextField">         <binding name="value" value="pageNum"/>
   </component>
   <component id="go" type="LinkSubmit">
<binding name="listener" value="listener:onPage"/>
<binding name="tag" value="pageNum"/>
<binding name="selected" value="selectedPage"/>
</component>
java代码:
public abstract int getPageNum();
    public void onPage(IRequestCycle objCycle)
{
System.out.println(getPageNum());
}
通过你提供的方法我这里面提交后组件ID是pageform,而监听方法是帮定在go这个元素上的,
lmb = (ListenerMethodBinding)this.getComponent(componentName).getBindings().get("listener");
lmb得到的null
0 请登录后投票
   发表时间:2006-12-22  
这周工作太忙...见谅.

确实存在这个问题.简单的解决办法就是
在String componentName = this.getRequestCycle().getParameter("component");后加上以下代码:
String submitname = this.getRequestCycle().getParameter("submitname");
if (submitname!=null && !"".equals(submitname))
  componentName = submitname;
0 请登录后投票
   发表时间:2006-12-25  
我这里还有一种情况也是获得不了的。
<form jwcid="taskForm@Form"  clientValidationEnabled="true"  >
<input jwcid="tasks@Submit" value="add"  listener="listener:addTask" />
这个时候也是获得不了的。因为有时候一个form里面有多个submit每个submit帮定的方法都是不同的,这个时候就不给form帮定方法了,而是给submit直接帮定。
另外:有时候在写成sucessful="listener:addTask"或者action="listener:addTask"这个时候也是获得不了的
0 请登录后投票
   发表时间:2006-12-26  
你可以在浏览器中的页面源代码中找到这个tasks,应该会有<input type="hidden" name="xxx" value="tasks"/>的语句(request.getParameter("xxx") )...解决办法同linksubmit....


T4的源码还有待研究...目前我也只能做到这种简洁一点的办法了!
0 请登录后投票
   发表时间:2006-12-26  
忙...
稍后给与答复...
0 请登录后投票
   发表时间:2007-02-13  
完整版已贴上去!!!!!

注:Tapesty 5 的URL已出现层次目录,可以通过Filter更容易的拦截页面权限.
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics