我将同步器令牌模式用于标准表单(useToken=true),但我找不到任何在Ajax上处理此问题的推荐方法。
编辑
自从发布了这篇文章之后,我已经推出了包含Grails现有模式的解决方案。
在jQuery ajax中,我发布了整个表单(其中包括Grails注入的SYNCHRONIZER_TOKEN和SYNCHRONIZER_URI隐藏字段),以便withForm闭包可以在控制器中按预期执行。
问题是,在成功响应时,没有新的令牌设置(因为页面没有重新加载,也没有调用g:form taglib),所以我在控制器中手动执行此操作,调用到与g:form taglib相同的库中,并在ajax响应中返回它,然后重置隐藏字段值。见下文:
var formData = jQuery("form[name=userform]").serializeArray();
$.ajax({
type: 'POST',
url: 'delete',
data: formData,
success: function (data) {
// do stuff
},
complete: function (data) {
// Reset the token on complete
$("#SYNCHRONIZER_TOKEN").val(data.newToken);
}
})
在控制器中:
def delete(String selectedCommonName) {
def messages = [:]
withForm {
User user = User.findByName(name)
if (user) {
userService.delete(user)
messages.info = message(code: 'user.deleted.text')
} else {
messages.error = message(code: 'user.notdeleted.text')
}
}.invalidToken {
messages.error = message(code: 'no.duplicate.submissions')
}
// Set a new token for CSRF protection
messages.newToken = SynchronizerTokensHolder.store(session).generateToken(params.SYNCHRONIZER_URI)
render messages as JSON
}
有没有人可以识别我是否在不知情的情况下在上述解决方案中引入了一个安全缺陷。它看起来足够我,但我不喜欢手滚任何与安全有关的事情。
不错!
IMO,你最好同时重置令牌。
synchronizerTokensholder.store(会话).resetToken(Params.synchronizer_URI)
如果在同一页面中有多个表单,则定义一个变量来保存从每个ajax请求返回的令牌。
顺便说一句,为什么不自己实现令牌模式呢?
uuid.randomuuid().toString()
,并以url作为密钥将其存储到会话中。