zoukankan      html  css  js  c++  java
  • JSF 监听

    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/

  • 相关阅读:
    实现Java中的ArrayList
    官方下拉刷新控件SwipeRefreshLayout的使用
    SpannableString的基本用法
    AlarmManager的使用
    在Android上使用Socket
    HttpURLConnection、HttpClient和Session
    Cocos2d入门及第一次运行时遇到的问题
    Thread的start和run的区别
    《重构》心得
    startActivityForResult()的用法(超好用啊)
  • 原文地址:https://www.cnblogs.com/lhfyy/p/4505956.html
Copyright © 2011-2022 走看看