使用spring security时如何在速度宏中获取csrf令牌

我正在尝试为启用spring web security的应用程序创建自定义登录屏幕,我无法弄清楚如何将csrf标记传递给velocity(不,我目前无法使用JSP)。

该模型看起来像这样:

@RequestMapping(value = "/login", method = RequestMethod.GET) public ModelAndView login( @RequestParam(value = "error", required = false) String error, @RequestParam(value = "logout", required = false) String logout ModelAndView model = new ModelAndView(); if (error != null) { model.addObject("error", "Invalid username or password!"); } if (logout != null) { model.addObject("msg", "You've been logged out successfully."); } model.setViewName("login"); return model; } 

并且速度模板的相关部分看起来像(从jsp示例中获取和修改):

  
User:
Password:

当然, ${_csrf.parameterName}${_csrf.token}变量都是空的,所以这只有在禁用csrf保护的情况下才有效。 所以我的主要问题是:如何在模型中(或其他任何地方)填充它们?

我找到了解决方案,主要的一点是csrfFilter将csrf令牌注入到HttpServletRequest中,只需在处理请求映射的方法中添加HttpServletRequest参数即可获取HttpServletRequest对象。

所以需要做的改变是:

 @RequestMapping(value = "/login", method = RequestMethod.GET) public ModelAndView login( @RequestParam(value = "error", required = false) String error, @RequestParam(value = "logout", required = false) String logout, HttpServletRequest request ){ ... CsrfToken csrfToken = (CsrfToken) request.getAttribute(CsrfToken.class.getName()); if (csrfToken != null) { model.addObject("_csrf",csrfToken); } ... 

为了分享我的一点点,我最初开始使用@P.Péter的解决方案,这很好。 但随着我的应用程序变得如此之多,我觉得使用该片段对于我需要保护免受csrf入侵的每个表单太麻烦了,所以这就是我所做的,所以我不必在我的应用程序中重复。

 @ControllerAdvice public class CsrfControllerAdvice { @Autowired private HttpServletRequest request; @ModelAttribute("_csrf") public CsrfToken appendCSRFToken(){ //HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest(); return (CsrfToken) request.getAttribute(CsrfToken.class.getName()); } } 

要点 – 想法是使用@ControllerAdvice ,在进入任何Spring Controller时调用它以使用@ModelAttribute("")注释将CsrfToken附加到生成的View。

注1 –_csrf模型属性为所有视图附加,因此如果要将_csrf处理限制为选定的URL或视图,请参阅此资源,以获取有关如何执行此操作的非常好的示例。

注2 –请注意我如何注释掉以下行?

 //HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest(); 

那是因为在我的情况下,Autowired HttpServletRequest实例足以满足我的场景。 但是,某些情况可能会保证您使用注释掉的实例,例如,当您需要从应用程序的某些部分获取请求对象时,该请求对象不一定是请求作用域…请参阅此线程中指出的@Samit G的答案更多信息。