Spring security 将CSRF令牌添加到所有表单提交中

Spring security 将CSRF令牌添加到所有表单提交中,spring-security,csrf,csrf-protection,Spring Security,Csrf,Csrf Protection,我最近在我的web应用程序中启用了CSRF保护。大约有100多个JSP页面包含表单提交。添加CSRF令牌的最佳方式是什么: <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/> 这样,所有提交的表单都将包含此表单数据。我不想将此参数添加到每个表单提交中。因此我终于找到了一个可行的解决方案。基本上,我创建了一个自定义FormRenderer,如下所示: import com.sun

我最近在我的web应用程序中启用了CSRF保护。大约有100多个JSP页面包含表单提交。添加CSRF令牌的最佳方式是什么:

<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/> 


这样,所有提交的表单都将包含此表单数据。我不想将此参数添加到每个表单提交中。

因此我终于找到了一个可行的解决方案。基本上,我创建了一个自定义FormRenderer,如下所示:

import com.sun.faces.renderkit.html_basic.FormRenderer;

import javax.el.ELContext;
import javax.el.ExpressionFactory;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import java.io.IOException;

public class FormWithCSRFRenderer extends FormRenderer {

    @Override
    public void encodeEnd(FacesContext context, UIComponent component) throws IOException {
        log.debug("FormWithCSRFRenderer - Adding CSRF Token to form element");
        ELContext elContext = context.getELContext();
        ExpressionFactory expFactory = context.getApplication().getExpressionFactory();

        ResponseWriter writer = context.getResponseWriter();
        writer.startElement("input", component);
        writer.writeAttribute("type", "hidden", null);
        writer.writeAttribute("name", expFactory.createValueExpression(elContext, "${_csrf.parameterName}", String.class).getValue(elContext), null);
        writer.writeAttribute("value", expFactory.createValueExpression(elContext, "${_csrf.token}", String.class).getValue(elContext), null);
        writer.endElement("input");
        writer.write("\n");
        super.encodeEnd(context, component);
    }
}
然后通过在
faces config.xml
中设置它来注册它以覆盖FormRenderer:

<?xml version="1.0" encoding="UTF-8"?>
<faces-config xmlns="http://xmlns.jcp.org/xml/ns/javaee"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_2.xsd"
              version="2.2">
    <render-kit>
        <renderer>
            <component-family>javax.faces.Form</component-family>
            <renderer-type>javax.faces.Form</renderer-type>
            <renderer-class>com.acme.FormWithCSRFRenderer</renderer-class>
        </renderer>
    </render-kit>
</faces-config>

javax.faces.Form
javax.faces.Form
com.acme.FormWithCSRFRenderer

我尝试创建一个组件,然后将其作为子组件添加,但它不允许我正确设置输入的名称,因此我直接编写它。

因此我终于找到了一个可行的解决方案。基本上,我创建了一个自定义FormRenderer,如下所示:

import com.sun.faces.renderkit.html_basic.FormRenderer;

import javax.el.ELContext;
import javax.el.ExpressionFactory;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import java.io.IOException;

public class FormWithCSRFRenderer extends FormRenderer {

    @Override
    public void encodeEnd(FacesContext context, UIComponent component) throws IOException {
        log.debug("FormWithCSRFRenderer - Adding CSRF Token to form element");
        ELContext elContext = context.getELContext();
        ExpressionFactory expFactory = context.getApplication().getExpressionFactory();

        ResponseWriter writer = context.getResponseWriter();
        writer.startElement("input", component);
        writer.writeAttribute("type", "hidden", null);
        writer.writeAttribute("name", expFactory.createValueExpression(elContext, "${_csrf.parameterName}", String.class).getValue(elContext), null);
        writer.writeAttribute("value", expFactory.createValueExpression(elContext, "${_csrf.token}", String.class).getValue(elContext), null);
        writer.endElement("input");
        writer.write("\n");
        super.encodeEnd(context, component);
    }
}
然后通过在
faces config.xml
中设置它来注册它以覆盖FormRenderer:

<?xml version="1.0" encoding="UTF-8"?>
<faces-config xmlns="http://xmlns.jcp.org/xml/ns/javaee"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_2.xsd"
              version="2.2">
    <render-kit>
        <renderer>
            <component-family>javax.faces.Form</component-family>
            <renderer-type>javax.faces.Form</renderer-type>
            <renderer-class>com.acme.FormWithCSRFRenderer</renderer-class>
        </renderer>
    </render-kit>
</faces-config>

javax.faces.Form
javax.faces.Form
com.acme.FormWithCSRFRenderer

我曾尝试创建一个组件,然后将其作为子组件添加,但它不允许我正确设置输入的名称,因此我直接编写它。

也许你想使用ajax?我正要问同样的问题,我也尝试创建自己的表单标记,但属性包含/传递到内部表单有点复杂。下一步是在呈现表单时重写表单行为。最简单的方法是使用javascript将此元素添加到每个form@TecHunter:部分还原的标记编辑。jsf和JavaEE与最初的问题毫无关系。。。您可以创建一个新的特定问题,自己回答或回答question@Kukeltje哦,我把这个问题误认为是jsf问题……也许你想使用ajax?我正要问同样的问题,我也试图创建自己的表单标记,但是属性有点复杂,无法包含/传递到内部表单。下一步是在呈现表单时重写表单行为。最简单的方法是使用javascript将此元素添加到每个form@TecHunter:部分还原的标记编辑。jsf和JavaEE与最初的问题毫无关系。。。您可以创建一个新的特定问题,自己回答或回答question@Kukeltje哦,我把这个问题误认为是jsf问题……为什么你需要这个?这解决了什么PrimeFaces还没有为您解决的问题?我还原了您的标记编辑,因为您添加了与原始问题完全不相关的标记(例如jsf)。为什么需要这个?这解决了什么PrimeFaces还没有为您解决的问题?我恢复了您的标记编辑,因为您添加了与原始问题完全无关的标记(例如jsf)。