1. 角色受限采访URL。由于JSF的流程在Servlet Filter之后, 所以不能使用Filter的层面获取到JSF的一些请求路径信息,即javax.faces.context.FacesContext.getCurrentInstance()应该是空的。这里可以使用javax.faces.event.PhaseListener来获取请求和输出路径信息。在face-config.xml配置好即可获取到请求和输出的页面路径。例如,用户当前处于公用页面A.jsf, 现在按链接想跳转到B.jsf; JSF首先会恢复A.jsf的视图,这时PhaseListener,验证合法就输出视图到B.jsf, 这时又会来到PhaseListener 恢复视图B.jsf, 可以将鉴权的代码添加到或BeforeParse, AfterParse方法里。 ParseListener对h:outputLink或CommandLink是应该是可行的,因为只是对链接进行限制。 如果对于CommandButton可能是不行的,例如A.jsf 点击按钮action="#{bBean.bAction}", public String bAction() ...{
//能够进入到方法内部,如果这里是很多逻辑操作,数据操作的话。。。。 return "B_JSF"; //只有在return之后ParseListener才能限制鉴权,那就晚了。而链接就不同,因为它没什么逻辑操作。 } 这种鉴权就要用到下面提到的第二种方法。 package web;
import java.io.IOException; import javax.faces.context.ExternalContext; import javax.faces.context.FacesContext; import javax.faces.event.PhaseEvent; import javax.faces.event.PhaseId; import javax.faces.event.PhaseListener; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** *//** * @author zealvampire * @version 1.0 2006-10-17 */ public class SecurityPhaseListener implements PhaseListener ...{ private static final long serialVersionUID = 6186106530012195240L; private static final Log log = LogFactory.getLog(SecurityPhaseListener.class); /**//* (non-Javadoc) * @see javax.faces.event.PhaseListener#afterPhase(javax.faces.event.PhaseEvent) */ 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 } /**//* (non-Javadoc) * @see javax.faces.event.PhaseListener#beforePhase(javax.faces.event.PhaseEvent) */ public void beforePhase(PhaseEvent event) ...{ } /** *//** * (non-Javadoc) * @see javax.faces.event.PhaseListener#getPhaseId() */ public PhaseId getPhaseId() ...{ return PhaseId.ANY_PHASE; } } face-config.xml <faces-config>
<lifecycle> <phase-listener> web.SecurityPhaseListener </phase-listener> </lifecycle> </face-config> 2. 扑获JSF中用户要执行的Action例子,用户在A.jsf点击CommandButton action="#{bBean.bAction}" 要是我们能在这个动作执行之前扑获到它并进行鉴权的话, 那就Sofu了。这个我是看Myfaces源码以及看face-config.xml格式看到的, 里面有个ActionListener, 猜猜是什么东西? 是的,就像写Swing一样,用来处理消息和动作的。先看看Myfaces的默认实现。 /**//*
* Copyright 2004 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www./licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.myfaces.application; import javax.faces.FacesException; import javax.faces.application.Application; import javax.faces.application.NavigationHandler; import javax.faces.component.ActionSource; 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; /** *//** * @author Manfred Geiler (latest modification by $Author: mbr $) * @author Anton Koinov * @version $Revision: 231425 $ $Date: 2005-08-11 07:49:45 -0400 (Thu, 11 Aug 2005) $ */ public class ActionListenerImpl implements ActionListener ...{ private static final Log log = LogFactory.getLog(ActionListenerImpl.class); public void processAction(ActionEvent actionEvent) throws AbortProcessingException ...{ FacesContext facesContext = FacesContext.getCurrentInstance(); Application application = facesContext.getApplication(); ActionSource actionSource = (ActionSource)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); } 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(); } } 看到fromAction = methodBinding.getExpressionString();这个你就偷笑了吧,那确实,这个就是我们要的bBean.bAction 模仿这个类重新写一个类吧,。然后在face-config.xml配置一下。 <application>
<variable-resolver> org.springframework.web.jsf.DelegatingVariableResolver </variable-resolver> <action-listener>OurOwnActionListenerImpl</action-listener> </application> ActionListener是一个接口,我想在其他JSF的实现,应该也是通过的吧。 3。 如果还有其他好的方案请和我们分享。 |
|