【问题标题】:How to obtain csrf token in a velocity macro when using spring security使用spring security时如何在velocity宏中获取csrf令牌
【发布时间】:2014-10-26 19:36:33
【问题描述】:

我正在尝试为启用 Spring Web 安全的应用程序创建自定义登录屏幕,但我不知道如何将 csrf 令牌传递给速度(不,我目前无法使用 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示例并进行了修改):

    <form name='loginForm' action="/login" method='POST'>
      <table>
        <tr>
            <td>User:</td>
            <td><input type='text' name='username' value=''></td>
        </tr>
        <tr>
            <td>Password:</td>
            <td><input type='password' name='password' /></td>
        </tr>
        <tr>
            <td colspan='2'><input name="submit" type="submit" value="submit" /></td>
        </tr>
      </table>
      <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
    </form>

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

【问题讨论】:

    标签: java spring velocity


    【解决方案1】:

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

    @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());
        }
    }
    

    POINT - 这个想法是使用@ControllerAdvice,它在进入任何 Spring Controller 时被调用,以使用 @ModelAttribute("&lt;attribute-name&gt;") 注释将 CsrfToken 附加到结果视图。

    注意 1 -_csrf 模型属性为所有视图附加,因此如果您想将_csrf 处理限制为选定的 URL 或视图,请参阅 this resource here 以获得非常好的示例关于如何做到这一点。

    注意 2 -注意我是如何注释掉以下行的?

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

    这是因为在我的情况下,Autowired HttpServletRequest 实例对于我的场景来说已经足够了。但是,某些情况可能保证您使用注释掉的实例,例如,当您需要从应用程序的某些部分获取请求对象时,不一定是请求范围......请参阅@Samit G 的答案,如this thread here 中指出的那样更多信息。

    【讨论】:

      【解决方案2】:

      我找到了解决办法,重点是csrf令牌是通过CsrfFilter注入到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);
          }
      ...
      

      【讨论】:

      • 您甚至可以将CsrfToken 直接注入到方法参数中,而无需处理请求
      猜你喜欢
      • 1970-01-01
      • 2014-04-26
      • 2019-12-19
      • 2014-12-06
      • 2015-05-10
      • 2017-09-07
      • 2012-03-06
      • 2019-07-20
      • 2014-07-03
      相关资源
      最近更新 更多