我正在尝试为启用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保护的情况下才有效。所以我的主要问题是:如何在模型中(或其他任何地方)填充它们?
答案 0 :(得分:5)
我找到了解决方案,主要的一点是csrfFilter将csrf令牌注入到HttpServletRequest中,只需在处理请求映射的方法中添加HttpServletRequest参数即可获取HttpServletRequest对象。 p>
所以需要做的改变是:
@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);
}
...
答案 1 :(得分:1)
为了分享我的一点点,我最初开始使用@P.Péter的解决方案,这很好。但是随着我的应用程序变得越来越多,我觉得使用该片段对于我需要保护的每个表单都没有csrf入侵过于繁琐,所以这就是我所做的,所以我不必在我的应用程序中重复。 / p>
<p>This is a paragraph.</p>
<select name="" id="legal-form">
<option value="v1">v1</option>
<option value="v2">v2</option>
<option value="v3">v3</option>
</select>
$('#legal-form').change(function(){
var x;
if($(this).val() == 'v2'){
x = $("p").detach();
} else {
$("body").prepend(x);
};
});
POINT - 我们的想法是使用一个@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());
}
}
来调用任何Spring Controller,使用@ControllerAdvice
注释将CsrfToken附加到生成的View。
注1 - 此@ModelAttribute("<attribute-name>")
模型属性附加了所有视图,因此如果您要将_csrf
处理限制为所选的网址或视图,请参阅{{3关于如何做到非常好的样本。
注意2 - 请注意我是如何注释掉以下行的?
_csrf
那是因为在我的情况下,Autowired //HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
实例足以支持我的场景。但是,某些情况可能会保证您使用注释掉的实例,例如,当您需要从应用程序的某个部分获取请求对象时,不一定是请求作用域...请参阅{{3}中指出的@Samit G的答案}了解更多信息。