Grails 中的自定义验证器中的异常
Posted
技术标签:
【中文标题】Grails 中的自定义验证器中的异常【英文标题】:Exception in custom validator in Grails 【发布时间】:2012-09-23 15:37:30 【问题描述】:我正在尝试在 Grais 中对通过 spring 安全核心插件创建的 User
域实体实施密码验证。我在我的实体中添加了以下代码:
class User
// Added by the spring security core plugin
String password
// Added by me
String passwordConfirm
static constraints =
passwordConfirm blank:false, validator: val, obj ->
if (!obj.password.equals(obj.passwordConfirm))
return "user.password.confirmation.error"
// other methods...
当password
与passwordConfirm
不匹配时,验证器会按预期工作。但是,当验证器成功通过并且实例即将被持久化时,我得到以下异常:
org.hibernate.AssertionFailure: null id in com.test.User entry (don't flush the Session after an exception occurs)
at com.shopify.RegistrationController$_closure2.doCall(RegistrationController.groovy:14)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:680)
我正在使用user.save(flush: true)
持久化我的实体。
当我删除验证时,我的实例已成功保存在数据库中,因此我认为我的验证器一定有问题。您对可能出现的问题有什么建议吗?我正在使用 grails 2.0.4 版。
编辑:我保存实体的部分如下:
def register =
def user = new User(params)
if (!user.save(flush:true, failOnError:true))
render view: 'register', model: [userInstance: user]
else
render view: 'success'
编辑:好的,我设法通过注释掉弹簧安全核心插入的以下代码来完成这项工作:
def beforeInsert()
// encodePassword()
def beforeUpdate()
// if (isDirty('password'))
// encodePassword()
//
目前,我不知道为什么会发生这种情况,但我会检查一下。同时,如果有人对此有任何信息,我真的很想与我分享。
编辑:发现这个相关的错误报告:http://jira.grails.org/browse/GRAILS-9083
【问题讨论】:
你能把这个添加到保存中以获得更详细的错误日志 user.save(flush: true, failOnError: true) 你能贴出保存 obj 的全部代码吗?而不仅仅是 user.save() 你的验证器应该比较obj.password
和val
(被验证的值)而不是obj.passwordConfirm
。
我试过了,但结果是一样的。
【参考方案1】:
验证失败,因为在插入您的用户之前,它会对您的密码进行哈希处理,因此密码不再等于密码确认,从而触发验证错误。
这是你正在做的事情:
在保存()之前:
def password = 1234
def passwordConfirm = 1234
password == passwordConfirm validation passes
在 .save() 期间。在触发插入之前:
def password gets hashed:
def password = 1JO@J$O!@J$P!O@$JP!@O$J!@O$J!@
def passwordConfirm = 1234
password != passwordConfirm validation fails
从您的域中删除 encodePassword() 后:
def password = 1234
def passwordConfirm = 1234
password == passwordConfirm validation passes but now you have your password in plain texts inside your DB, you should never do this for security reasons.
简单的解决方法是在单独的命令对象中进行验证,而不是在它自己的域对象中,passwordConfirm 甚至不应该在你的域类中。
示例: 看看 Spring Security UI 的 source,看看它如何使用命令对象处理控制器中的验证。
【讨论】:
我没有收到验证错误,我收到了异常。不确定是不是这样。 如果您阅读了您链接的 JIRA 票证的评论部分,您会注意到它也是由验证失败引起的,以及未显示错误的原因。以上是关于Grails 中的自定义验证器中的异常的主要内容,如果未能解决你的问题,请参考以下文章