Spring 引导 Groovy 模板未将 _csrf 添加到模型

Spring Boot Groovy Templates Not Adding _csrf to model

我有一个非常简单的 Spring 引导应用程序,它由一个主要的 Application.java(使用默认的主要方法)、一个 MainController(它有一个到 /login 的 requestMapping)和一个 SecurityConfig 组成(主要是默认值)。

我的问题是 Groovy 模板中的 _csrf 支持。 FreeMarker 一切正常,但是当我切换到 GroovyTemplates 时,_csrf 参数没有被放入模型中。

Groovy 模板中是否存在错误,我必须手动执行某些操作才能获取令牌,或者是否缺少某些配置步骤(尽管我不知道为什么会起作用对于 FreeMarker) ?

更新:

我在 login.tpl(Groovy 模板)上打印了 this.properties(HashMap):

{class=class login, out=java.io.BufferedWriter@5e2aead3, model={error=Optional.empty, org.springframework.validation.BindingResult.error=org.springframework.validation.BeanPropertyBindingResult: 0 errors, spring=org.springframework.web.servlet.support.RequestContext@1d99fb33, springMacroRequestContext=org.springframework.web.servlet.support.RequestContext@7fcc5c78}}

属性映射中的模型键包含参数

我使用以下方法在控制器操作中添加了错误:

@RequestMapping(value="/login", method = RequestMethod.GET)
public ModelAndView login(@RequestParam Optional<String> error) {
    return new ModelAndView("views/login", "error", error);
}

当使用 GroovyMarkupViewGroovyMarkupViewResolver 时,视图的属性仅包含模型中可用的属性(有些是为 Groovy 添加的)。

要包含请求属性,请将 GroovyMarkupViewResolverexposeRequestAttributes 属性 设置为 true。理想情况下,这是通过在 application.properties.

中设置以下 属性 来完成的
spring.groovy.template.exposeRequestAttributes=true

但是由于 this issue 目前无法实现。

要解决它,请创建一个 BeanPostProcessor,它检查传入的 bean 是否是 GroovyMarkupViewResolver(如果您想要更通用的方法,则为 AbstractTemplateViewResolver)。如果是这样,请将 exposeRequestAttributes 设置为 true。

public class TemplateViewResolverPostProcessor implements BeanPostProcessor {

    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {

        if (bean instance GroovyMarkupViewResolver) {
            ((GroovyMarkupViewResolver) bean).setExposeRequestAttributes(true);
        }
        return bean;
    }

    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }
}

完成后 CsfrToken 可用键 _csfr,请注意这是实际的 CsfrToken

另一个解决方案是创建一个 HandlerInterceptor 实现 postHandle 方法并将 _csfr 属性 添加到模型中。这样你就可以简单地添加令牌的值而不是实际的令牌本身。这将适用于任何使用的视图技术。

public class CsrfAddingInterceptor extends HandlerInterceptorAdapter {

    public void postHandle(HttpServletRequest req, HttpServletResponse res, Object handler, ModelAndView mav) throws Exception {
        CsrfToken token = (CsrfToken) req.getAttribute(CsrfToken.class.getName())
        if (token != null) {
            mav.addAttribute(token.getParameterName(), token.getToken());
        }
    }

}

然后将其添加为拦截器,您将获得可用的值。

所以处理这个问题的破解方法是手动将 _csrf 属性添加到控制器中的模型。例如:

model.addAttribute( "_csrf", request.getAttribute("_csrf") );

如果您的服务器上有很多视图,我不建议这样做。我建议您遵循@M-Deinnum 的其中一个选项。但是,为了快速测试,这是可行的。