Grails中自定义验证程序中的异常

时间:2012-10-02 18:31:51

标签: hibernate validation grails spring-security gorm

我正在尝试在通过spring security core plugin创建的User域实体上的Grais中实现密码验证。我在我的实体中添加了以下代码:

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

1 个答案:

答案 0 :(得分:0)

验证失败,因为在插入用户之前,它会散列您的密码,因此密码不再等于passwordConfirm,从而触发验证错误。

这是你在做什么:

保存前的

:(

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,了解它如何使用命令对象处理控制器中的验证。