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...

passwordpasswordConfirm 不匹配时,验证器会按预期工作。但是,当验证器成功通过并且实例即将被持久化时,我得到以下异常:

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.passwordval(被验证的值)而不是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 中的自定义验证器中的异常的主要内容,如果未能解决你的问题,请参考以下文章

来自另一个域类的属性的 Grails 自定义验证器

Grails 条件可空验证或具有可空选项的自定义验证器

Laravel 5 中的自定义验证器

将预定义的验证器添加到 Angular 中的自定义组件

Grails中的电子邮件验证

Parsley.js 中的自定义正则表达式验证器