Grails尝试验证编码密码(Spring Security Core)

时间:2013-11-22 20:54:20

标签: spring validation grails spring-security

我花了好几个小时没有找到解决方案。其他问题也很接近,但建议的解决方案都不适合我。

我正在运行 - Grails 2.1.1与
安装 - Groovy 2.0.8和
- Oracle Java v 1.6.0_45(也已经尝试过1.7)

我添加了Spring Security Core Plugin v 2.0-RC2 我是Grails的初学者,我想做的就是使用我自己的密码验证器创建一个带有密码的“Runner”。

这是我的Runner.groovy域类(除了重命名之外,默认的Spring Security User模板没有太大变化):

package de.muden.runnerbase

class Runner {

transient springSecurityService

String username
String password
boolean enabled = true
boolean accountExpired
boolean accountLocked
boolean passwordExpired

Date dateCreated
Profile profile

public static final int MIN_PASS_LENGTH = 6
public static final int MAX_PASS_LENGTH = 20

static transients = ['springSecurityService']

static constraints = {
    username(size:3..20,unique:true)
    password(nullable:false, blank:false, minSize:6, validator: { passwd, runner ->
        return (passwd != runner.username && validatePasswordInplace(passwd))
    })
    dateCreated()
    profile(nullable:true)
}

static mapping = {
    profile lazy:false
    runs sort:'dateCreated'
    password column: '`password`'
}

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

def beforeInsert() {
    encodePassword()
}

def beforeUpdate() {
    if (isDirty('password')) {
        encodePassword()
    }
}

String toString() {
    return "Runner '$username'"
}

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

protected static boolean validatePasswordInplace(String passToValidate) {
    println "VALIDATING PASS $passToValidate"
    return passToValidate ==~ /([A-Za-z0-9äöüÄÖÜß.!\?_-]){$MIN_PASS_LENGTH,$MAX_PASS_LENGTH}/
}

static hasMany = [runs: Run, shoes: Shoe]
}

因此验证器允许长度为6到20个字符的密码,大写和小写字母,数字和一些特殊字符。 仅测试此方法的简单单元测试按预期工作。

现在进行简单的集成测试:

void testValidRunner() {
    Runner r = new Runner(username:'dummy',password:'foobar')
    assertTrue r.validate()   // OK
    assertFalse r.hasErrors()  // OK        
    assertNotNull r.save(flush:true,failOnError:true)     // OK

    Runner foundRunner = Runner.findByUsername("dummy")
    assertNotNull foundRunner         // fails, foundRunner = null
    assertEquals('dummy',foundRunner.username)
}

控制台(用-echoOut)说:

VALIDATING PASS foobar
VALIDATING PASS $2a$10$Q5RYaDrCFFxdXEqYqV4J2OJWHzgOJZJ3wljqVK1jNP4Sqm6ZUOPam

很明显,第二次验证失败了。但为什么grails会再次验证编码密码?为什么r.validate()不抱怨?第二次验证究竟发生在哪里?

我觉得我在这里做了非常基本的用户密码加密错误...

首先我认为它与添加的Spring Security字段“accountExpired”等有关,而不是在约束块中。但是当我删除自定义验证器时,一切正常。

感谢任何帮助: - )

谢谢, 马特

1 个答案:

答案 0 :(得分:0)

以下是我的想法...

  1. 当您调用r.save
  2. 时,会发生第二次验证
  3. beforeInsert方法调用encodePassword方法,该方法将PW编码为长字符串$ 2a $ 10 $ Q5RYaDrCFFxdXEqYqV4J2OJWHzgOJZJ3wljqVK1jNP4Sqm6ZUOPam
  4. 这是将在DB中验证并保存的字符串'foobar'
  5. 我相信你的正则表达式不允许美元符号,这是编码字符串的一部分导致失败。
  6. 我不认为使用约束会对您想要做的事情起作用。您需要在编码之前进行验证,因此您可能需要添加单独的验证代码(在域类或其他地方)并在分配到PW字段并保存对象之前验证PW。