角色受限采访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.apache.org/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的实现,应该也是通过的吧。
由于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.apache.org/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的实现,应该也是通过的吧。