0

我正在尝试User在通过 Spring Security 核心插件创建的域实体上在 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...
}

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

4

1 回答 1

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

于 2012-10-02T21:28:03.733 回答