繁体   English   中英

使用Spring Security时如何在速度宏中获取CSRF令牌

[英]How to obtain csrf token in a velocity macro when using spring security

我试图为启用了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示例):

    <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保护的情况下才有效。 所以我的主要问题是:如何将它们填充到模型中(或其他任何地方)?

我已经找到了解决方案,要点是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);
    }
...

只是分享一点,我最初是使用@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("<attribute-name>")批注将CsrfToken附加到结果视图。

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

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM