JSF项目中实现基于RBAC模型的权限管理设计(二) 转

4.3 权限验证模块设计

一个好的权限管理机制在项目中应用时,最好不要让程序员在具体业务代码的方法中来判断用户权限。因为这意味着大量重复的代码。同时,也会导致权限机制的修改造成所有业务代码都需要修改一遍。

最好办法是实现与具体业务代码无关的独立的权限验证模块。这个模块可以拦截用户对资源的访问请求,并且在该请求被实施前做出权限判断,将权限不符的访问导向警告或提示页面。

在普通的JSP项目中,我们往往会利用Tomcat的Servlet filter机制来实现这样的功能,但filter机制的颗粒度不够,无法做到ACTION级别。另一个问题是,在JSF项目中,页面的跳转默认使用的是Forward形式,而不是redirect形式的URL重定向,因此Filter往往无法截获页面的转向。

因此,在JSF项目中我们首先需要解决如何截获到用户对资源的访问的问题。

4.3.1 捕获URL级别的资源访问

在JSF中,我们有时候会使用PhaseListener观察JSF生命周期,这给我们一个思路,通过PhaseListener 可以在一个点上(JSF生命周期的Restore View phase阶段)来获取请求和输出路径信息(这个路径实际上就是我们定义的URL类型的资源)。路径获取后我们就可以据此进行鉴权,从而避免在每个页面或者每个backing bean中判断用户访问权限,造成过多的冗余代码和管理上的混乱。

步骤一:在faces-config.xml中注册 自定义的PhaseListener。

<lifecycle>      <phase-listener>com.laomao.view.listener.PermissionPhaseListener</phase-listener>

</lifecycle>

步骤二:实现我们自己的PhaseListener接口

package com.laomao.view.listener;

import javax.el.MethodExpression;

import javax.faces.FacesException;

import javax.faces.application.Application;

import javax.faces.application.NavigationHandler;

import javax.faces.context.FacesContext;

import javax.faces.event.PhaseEvent;

import javax.faces.event.PhaseId;

import javax.faces.event.PhaseListener;

import org.apache.commons.logging.Log;

import org.apache.commons.logging.LogFactory;

public class PermissionPhaseListener implements PhaseListener {

private static Log log = LogFactory.getLog(PermissionPhaseListener.class);

@Override

public void afterPhase(PhaseEvent event) {

PhaseId phaseId = event.getPhaseId();

if (phaseId == PhaseId.RESTORE_VIEW || phaseId == PhaseId.INVOKE_APPLICATION) {

FacesContext currentContext = FacesContext.getCurrentInstance();

String viewId= currentContext.getViewRoot().getViewId();

//ViewId 就是我们需要的路径,类似URL,如/noPermission.xhtml

System.out.println("afterPhase: " + viewId);

//判断用户的操作权限

boolean isEnabled = true;

//TODO: 鉴权代码

//…

if(!isEnabled){

gotoNoPermissionPage();

}

}

}

/**

* 转入无权限声明页面

@param expression

*/

private void gotoNoPermissionPage() {

FacesContext context = FacesContext.getCurrentInstance();

Application application = context.getApplication();

NavigationHandler navHandler = application.getNavigationHandler();

navHandler.handleNavigation(context, null, Constants.NAVIGATION_NO_PERMISSION);

context.renderResponse();

}

}

PhaseListener可以捕获到URL的变化,对于页面内部的操作则无能为力了。例如CommandButton的操作,可能删除了一条记录,但URL却没有变化,仅仅是页面局部进行了刷新。因此,我们还需要一个可以捕获到用户对ACTION类型的资源的访问的利器。这个利器就是ActionListener。

4.3.2 捕获ACTION级别的资源访问

当一个按钮被按下,或者命令联结被点击时,JSF会在invork application阶段的broadcast

event时通过ActionListener调用事先绑定的事件处理方法。如果有用户自定义的ActionListener时,JSF将使用用户自定义ActionListener来代替默认的ActionListener。

用户自定义ActionListener必须实现javax.faces.event.ActionListener接口,并实现其接口方法:public void processAction(ActionEvent actionEvent)。

注意,在这个实现方法里,必须调用控件的事件处理方法(JSF Backing Bean中的事件处理方法),并对其返回值做出画面迁移处理和其他你自己的处理等。

步骤一:在faces-config.xml中注册 自定义的ActionListener。

<application>       <action-listener>com.laomao.view.listener.ActionListenerImpl</action-listener>

</application>

步骤二:实现我们自己的ActionListener接口

package com.laomao.view.listener;

import javax.el.ELContext;

import javax.el.MethodExpression;

import javax.faces.FacesException;

import javax.faces.application.Application;

import javax.faces.application.NavigationHandler;

import javax.faces.component.ActionSource2;

import javax.faces.context.FacesContext;

import javax.faces.el.EvaluationException;

import javax.faces.el.MethodBinding;

import javax.faces.event.AbortProcessingException;

import javax.faces.event.ActionEvent;

import javax.faces.event.ActionListener;

import org.apache.commons.logging.Log;

import org.apache.commons.logging.LogFactory;

public class ActionListenerImpl implements ActionListener {

private static Log log = LogFactory.getLog(PermissionPhaseListener.class);

@Override

public void processAction(ActionEvent actionEvent) throws AbortProcessingException {

FacesContext facesContext = FacesContext.getCurrentInstance();

Application application = facesContext.getApplication();

ActionSource2 actionSource = (ActionSource2)actionEvent.getComponent();

MethodBinding methodBinding = actionSource.getAction();

String fromAction;

String outcome;

if (methodBinding == null)

{

fromAction = null;

outcome = null;

}

else

{

fromAction = methodBinding.getExpressionString();

try

{

outcome = (String) methodBinding.invoke(facesContext, null);

//fromAction与faces-config.xml中登记的是一致的

//fromAction: #{loginController.loginAction}, outcome: success

System.out.println("fromAction: " + fromAction + ", outcome: " + outcome);

boolean isEnabled = true;

//TODO: 鉴权代码

//…

if(!isEnabled){

//如果无此权限,转到权限不足页面

gotoNoPermissionPage(actionSource.getActionExpression());

}

}

catch (EvaluationException e)

{

Throwable cause = e.getCause();

if (cause != null && cause instanceof AbortProcessingException)

{

throw (AbortProcessingException)cause;

}

else

{

throw new FacesException("Error calling action method of component with id " + actionEvent.getComponent().getClientId(facesContext), e);

}

}

catch (RuntimeException e)

{

throw new FacesException("Error calling action method of component with id " + actionEvent.getComponent().getClientId(facesContext), e);

}

}

NavigationHandler navigationHandler = application.getNavigationHandler();

navigationHandler.handleNavigation(facesContext,fromAction,outcome);

//Render Response if needed

facesContext.renderResponse();

}

/**

* 转入无权限声明页面

* @param expression

*/

private void gotoNoPermissionPage(MethodExpression expression) {

FacesContext context = FacesContext.getCurrentInstance();

Application application = context.getApplication();

NavigationHandler navHandler = application.getNavigationHandler();

navHandler.handleNavigation(context, null == expression ? null : expression.getExpressionString(), Constants.NAVIGATION_NO_PERMISSION);

context.renderResponse();

}

}

转:http://laomaowww.blog.163.com/blog/static/16600567320124751827427/

JSF 监听的更多相关文章

  1. 学习ASP.NET Core, 怎能不了解请求处理管道[3]: 自定义一个服务器感受一下管道是如何监听、接收和响应请求的

    我们在<服务器在管道中的"龙头"地位>中对ASP.NET Core默认提供的具有跨平台能力的KestrelServer进行了介绍,为了让读者朋友们对管道中的服务器具有更 ...

  2. 【用户交互】APP没有退出前台但改变系统属性如何实时更新UI?监听系统广播,让用户交互更舒心~

    前日,一小伙伴问我一个问题,说它解决了半天都没解决这个问题,截图如下: 大概楼主理解如下: 如果在应用中有一个判断wifi的开关和一个当前音量大小的seekbar以及一个获取当前电量多少的按钮,想知道 ...

  3. Java中用得比较顺手的事件监听

    第一次听说监听是三年前,做一个webGIS的项目,当时对Listener的印象就是个"监视器",监视着界面的一举一动,一有动静就触发对应的响应. 一.概述 通过对界面的某一或某些操 ...

  4. Android开发-之监听button点击事件

    一.实现button点击事件的方法 实现button点击事件的监听方法有很多种,这里总结了常用的四种方法: 1.匿名内部类 2.外部类(独立类) 3.实现OnClickListener接口 4.添加X ...

  5. 【WCF】终结点的监听地址

    终结点主要作用是向客户端公开一些信息入口,通过这个入口,可以找到要调用的服务操作.通常,终结点会使用三个要素来表述,我记得老蒋(网名:Artech,在园子里可以找到他)在他有关WCF的书里,把这三要素 ...

  6. ASP.NET Core真实管道详解[2]:Server是如何完成针对请求的监听、接收与响应的【上】

    Server是ASP .NET Core管道的第一个节点,负责完整请求的监听和接收,最终对请求的响应同样也由它完成.Server是我们对所有实现了IServer接口的所有类型以及对应对象的统称,如下面 ...

  7. 4.JAVA之GUI编程事件监听机制

    事件监听机制的特点: 1.事件源 2.事件 3.监听器 4.事件处理 事件源:就是awt包或者swing包中的那些图形用户界面组件.(如:按钮) 事件:每一个事件源都有自己特点有的对应事件和共性事件. ...

  8. Android ScrollView监听滑动到顶部和底部的两种方式(你可能不知道的细节)

    Android ScrollView监听滑动到顶部和底部,虽然网上很多资料都有说,但是不全,而且有些细节没说清楚 使用场景: 1. 做一些复杂动画的时候,需要动态判断当前的ScrollView是否滚动 ...

  9. Android来电监听和去电监听

    我觉得写文章就得写得有用一些的,必须要有自己的思想,关于来电去电监听将按照下面三个问题展开 1.监听来电去电有什么用? 2.怎么监听,来电去电监听方式一样吗? 3.实战,有什么需要特别注意地方? 监听 ...

随机推荐

  1. linuc c 代码示例

    fork的应用: #include "stdio.h" #include "string.h" #include <sys/types.h> #in ...

  2. 图片_ _图片缓存之内存缓存技术LruCache,软引用

    每当碰到一些大图片的时候,我们如果不对图片进行处理就会报OOM异常,这个问题曾经让我觉得很烦恼,后来终于得到了解决,那么现在就让我和大家一起分享一下吧.这篇博文要讲的图片缓存机制,我接触到的有两钟,一 ...

  3. GC之一--GC 的算法分析、垃圾收集器、内存分配策略介绍

    一.概述 垃圾收集 Garbage Collection 通常被称为“GC”,它诞生于1960年 MIT 的 Lisp 语言,经过半个多世纪,目前已经十分成熟了. jvm 中,程序计数器.虚拟机栈.本 ...

  4. 防止sql注入。xss攻击 方法

    //防止sql注入.xss攻击    /**     * 过滤参数     * @param string $str 接受的参数     * @return string     */    publ ...

  5. Yii 框架表单验证---实例

  6. eclipse ide for java ee developers 开发环境搭建(j2ee)

    转载自:http://www.iteye.com/topic/982182 真的是一片很不错的文章啊! 使用eclipse真的有年头了,相信java程序员没有不知道它的,最近在给团队中新来的应届生做指 ...

  7. Python标准库——走马观花

    作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! Python有一套很有用的标准库(standard library).标准库会随着 ...

  8. 要件审判九步法及其基本价值 z

    要件审判九步法及其基本价值 发布时间:2014-12-24 14:29:05 作者介绍 邹碧华,男,1967年出生于江西奉新,毕业于北京大学法学院,获法学博士学位.上海市高级人民法院副院长.2006年 ...

  9. $.ajax获取不到数据问题解决

    $("#updateflow").click(function () { $.ajaxSetup({ contentType: "application/json;cha ...

  10. JDBC中的事务-Transaction

    事务-Transaction 某些情况下我们希望对数据库的某一操作要么整体成功,要么整体失败,经典的例子就是支付宝提现.例如我们发起了支付宝到银行卡的100元提现申请,我们希望的结果是支付宝余额减少1 ...