我正在使用 JSF 2.2。我正在尝试将 JSF 用作纯模板语言。但是,有一个问题。在我的环境中创建 JSF 页面的任何用户都可以执行以下操作:
#{session.getAttribute('user').getApiKey()}
在这里,我有一个存储在会话中的用户对象,getApiKey() 方法是该类中的 getter。
是否有“web.xml”配置或其他一些技巧可以用来在 JSF 页面上完全禁用会话对象?
是否有“web.xml”配置或其他一些技巧可以用来在 JSF 页面上完全禁用会话对象?
不。
根据允许的标签、属性和 EL 表达式的白名单手动解析模板(注意:不要使用黑名单,黑客会找到你想不到的方法)。例如,以下表达式与 具有相同的效果#{session.getAttribute('user').getApiKey()}
:
#{request.session.getAttribute('user').apiKey}
#{sessionScope.user.apiKey}
#{user.apiKey}
#{facesContext.externalContext.sessionMap.user.apiKey}
#{facesContext.externalContext.session.getAttribute('user').apiKey}
毕竟,JSF/Facelets 可能是错误的工具,无法为客户提供某种将在服务器中执行的模板。而是寻找类似BB / Wiki / Markdown的标记或您通过.<h:outputText escape="false">
也许。隐式变量由特定的 ELResolver 提供。从 ELResolvers 列表中删除那个,或者添加一个自己的解析器,该解析器总是为该列表的所有隐式变量返回 null,应该可以解决问题。
顺便说一句,我不知道 JSF 是否提供了一个公共 API 来做这件事,或者规范甚至允许这样的事情。
无论哪种方式,如果您只需要一个模板引擎,有更简单的选项可以定制一个有状态的、基于组件的 Web 应用程序框架......
这是我为解决这个问题所做的。这个类本质上撤销了对页面上所有核心对象的访问。此外,我添加了一个实用程序变量来访问上下文路径。我试过这个,它似乎工作!.
package com.example.templates.jsf;
import javax.el.ELContext;
import javax.el.ELException;
import javax.el.PropertyNotFoundException;
import javax.faces.component.UIComponent;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import com.sun.faces.component.CompositeComponentStackManager;
import com.sun.faces.el.ImplicitObjectELResolver;
import com.sun.faces.util.MessageUtils;
/**
* This class revokes access to server page context objects
*/
public class CustomImplicitObjectELResolver extends ImplicitObjectELResolver {
public static final int CONTEXT_PATH = 19;
public CustomImplicitObjectELResolver(){
super();
// Revoke access to variables that can potentially
// give access to internal class objects.
IMPLICIT_OBJECTS.remove("facesContext");
IMPLICIT_OBJECTS.remove("session");
IMPLICIT_OBJECTS.remove("sessionScope");
IMPLICIT_OBJECTS.remove("application");
IMPLICIT_OBJECTS.remove("applicationScope");
IMPLICIT_OBJECTS.remove("request");
IMPLICIT_OBJECTS.remove("requestScope");
IMPLICIT_OBJECTS.remove("view");
IMPLICIT_OBJECTS.remove("viewScope");
IMPLICIT_OBJECTS.remove("initParam");
IMPLICIT_OBJECTS.remove("component");
IMPLICIT_OBJECTS.remove("cookie");
IMPLICIT_OBJECTS.remove("header");
IMPLICIT_OBJECTS.remove("headerValues");
IMPLICIT_OBJECTS.remove("flowScope");
// My own utility method
IMPLICIT_OBJECTS.put("contextPath", CONTEXT_PATH);
}
@Override
public Object getValue(ELContext context,Object base, Object property)
throws ELException {
// variable resolution is a special case of property resolution
// where the base is null.
if (base != null) {
return null;
}
if (property == null) {
String message = MessageUtils.getExceptionMessageString
(MessageUtils.NULL_PARAMETERS_ERROR_MESSAGE_ID, "property");
throw new PropertyNotFoundException(message);
}
Integer index = IMPLICIT_OBJECTS.get(property.toString());
if (index == null) {
return null;
} else {
FacesContext facesContext = (FacesContext) context.getContext(FacesContext.class);
ExternalContext extCtx = facesContext.getExternalContext();
switch (index) {
case COMPOSITE_COMPONENT:
// The following five lines violate the specification.
// The specification states that the 'cc' implicit object
// always evaluates to the current composite component,
// however, this isn't desirable behavior when passing
// attributes between nested composite components, so we
// need to alter the behavior so that the components behave
// as the user would expect.
/* BEGIN DEVIATION */
CompositeComponentStackManager manager =
CompositeComponentStackManager.getManager(facesContext);
Object o = manager.peek();
/* END DEVIATION */
if (o == null) {
o = UIComponent.getCurrentCompositeComponent(facesContext);
}
context.setPropertyResolved(o != null);
return o;
case PARAM:
context.setPropertyResolved(true);
return extCtx.getRequestParameterMap();
case PARAM_VALUES:
context.setPropertyResolved(true);
return extCtx.getRequestParameterValuesMap();
case CONTEXT_PATH:
context.setPropertyResolved(true);
return extCtx.getRequestContextPath();
case RESOURCE:
context.setPropertyResolved(true);
return facesContext.getApplication().getResourceHandler();
default:
return null;
}
}
}
}
接下来,在 faces-config.xml 中,添加以下条目:
<application>
<el-resolver>
com.example.templates.jsf.CustomImplicitObjectELResolver
</el-resolver>
</application>