无法解决 Grails 自定义验证器问题

Posted

技术标签:

【中文标题】无法解决 Grails 自定义验证器问题【英文标题】:Unable to resolve Grails custom validator issue 【发布时间】:2014-06-24 07:33:12 【问题描述】:

我在我的 grails 项目中使用 spring security core 插件,Person 域看起来像这样。

class User 

transient springSecurityService

//Mandatory Fields
String employeeId
String firstName
String lastName
String password
String emailId

//Other Fields
String department
String extn

String mobileNumber
String address
String city
String zipCode
String country

User manager

static hasMany = [previousPasswords: String]

boolean enabled = true
boolean accountExpired
boolean accountLocked
boolean passwordExpired

static transients = ['springSecurityService']

static constraints = 
    employeeId blank: false, unique: true
    firstName blank: false
    lastName blank: false
    password blank: false, password: true, validator: val, obj ->
        if(obj.previousPasswords) 
            println "-----------------------1-------------------------"
            println "obj.previousPasswords: " + obj.previousPasswords
            println "val: " + val
            if (obj.isDirty('password')) 
                println "-----------------------2-------------------------"
                if(obj.previousPasswords.contains(val)) 
                    obj.errors.rejectValue(
                        'password',
                        'user.password.duplicated',
                        'Repeat passwords are not allowed')
                    return false
                
                println "-----------------------3-------------------------"
                obj.addToPreviousPasswords(val)
                return true
            
         else 
            println "-----------------------4-------------------------"
            obj.addToPreviousPasswords(val)
            return true
        
    
    emailId blank: false, email: true

    department nullable: true
    extn nullable: true

    mobileNumber nullable: true
    address nullable: true
    city nullable: true
    zipCode nullable: true
    country nullable: true

    manager nullable: true


static mapping = 
    password column: '`password`'


Set<Role> getAuthorities() 
    UserRole.findAllByUser(this).collect  it.role  as Set


def beforeInsert() 
    println "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%"
    encodePassword()


def beforeUpdate() 
    if (isDirty('password')) 
        println "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"
        encodePassword()
    


protected void encodePassword() 
    password = springSecurityService.encodePassword(password)


我必须确保密码不会重复,我已经为“密码”字段编写了自定义验证器

我的集成测试如下所示

void "Test if previous passwords can be re-used"() 
    given:
    def user = new User(employeeId: "empId1", firstName: "f_name", lastName: "l_name", password: "password", emailId: "test@hptest.com", mobileNumber: "(111) 111-1111", address: "350 Fifth Avenue, 34th floor", city: "New York", zipCode: "10007")
    println "&&&&&&&&&&&&&&&&&&&  1  &&&&&&&&&&&&&&&&&&&&&&"
    user.springSecurityService = springSecurityService
    println "&&&&&&&&&&&&&&&&&&&  2  &&&&&&&&&&&&&&&&&&&&&&"
    user.save(flush: true, failOnError: true)

    when: 'password is repeated'
    user.password = "password"
    println "&&&&&&&&&&&&&&&&&&&  3  &&&&&&&&&&&&&&&&&&&&&&"
    user.save(flush: true)

    then: 'validation fails'
    !user.validate()
    user.errors.getFieldError("password").codes.contains("validator.invalid")

    when: 'password is not repeated'
    user.password = "password@123"

    then: 'validation succeeds'
    println "&&&&&&&&&&&&&&&&&&&  4  &&&&&&&&&&&&&&&&&&&&&&"
    user.validate()
    println "&&&&&&&&&&&&&&&&&&&  5  &&&&&&&&&&&&&&&&&&&&&&"
    user.save(flush: true)

我得到的输出是这样的

&&&&&&&&&&&&&&&&&&&  1  &&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&  2  &&&&&&&&&&&&&&&&&&&&&&
-----------------------4-------------------------
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-----------------------1-------------------------
obj.previousPasswords: [password]
val: $2a$10$mxFM9S7mEoOdyRo6xJL9/uzVafUgc0.8r1rd4nzBYM45s2cE8TTDi
&&&&&&&&&&&&&&&&&&&  3  &&&&&&&&&&&&&&&&&&&&&&
-----------------------1-------------------------
obj.previousPasswords: [password]
val: password
-----------------------2-------------------------
-----------------------1-------------------------
obj.previousPasswords: [password]
val: password

如果您仔细研究代码和输出,您会发现每次保存操作都会调用验证器函数两次。

谁能告诉我这是什么原因。这可能是由于我在验证器中使用的 addTo 方法造成的吗?

【问题讨论】:

唯一约束怎么样? 唯一约束应该不是问题。它已为employeeId 定义。问题出现在密码的自定义验证器中。 你也可以为此应用相同的约束。已经存在,为什么要自定义验证? 唯一约束意味着不同用户的密码不能相同。我的要求不一样。我想确保用户不使用他们以前使用过的密码。 哦,好的。我现在明白了。这就像更改密码对吗? 【参考方案1】:

我可以告诉另一种方式。删除自定义验证。

当用户更改密码时,检查此密码是否已经存在于previousPasswords中。如果存在,则给出已使用的消息。如果没有,将用户保存新密码并将其添加到previousPasswords中。

 def changePassword()
       def userIns = User.get(params.userId)
       def previousPasswords = userIns.previousPasswords()
       def exists = previousPasswords.findit == params.newPassword
       if(exists)
           msg = "Already Used. Give new"
           render changepassword screen
           return false
       
       else
           userIns.password = params.newPw
           userIns.addToPreviousPasswords(params.newPw)
           userIns.save(flush:true)
           msg = "successfully changed"
       
    

【讨论】:

嗯。周围的工作似乎值得一试。会尝试让您知道。 你用的是什么grails版本? 我还没有做。今天可能会完成。 删除自定义验证并清除目标文件夹下的类,如果您遇到任何问题。您使用的是什么 grils 版本? 我按照您的建议更改了代码并且它有效。谢谢。我正在使用 grails 2.3.7。

以上是关于无法解决 Grails 自定义验证器问题的主要内容,如果未能解决你的问题,请参考以下文章

Grails - 从自定义验证器闭包调用内置约束

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

在自定义验证器中使用标准验证器进行 Grails 验证

Grails 2.2.4:瞬态属性:为啥自定义验证器被调用两次?

Grails 中的自定义验证器中的异常

没有这个的grails 3.1.10自定义验证器问题。定义