问题
If I write the following code:
static constraints = {
password blank: false, password: true , validator:{ val, obj ->
if (obj.password != obj.confirmarPassword)
return 'usuario.password.dontmatch'
}
confirmarPassword bindable: true
}
}
static transients = ['confirmarPassword']
The following error appears after introducing the same password in password and confirmarPassword:
null id in usuario.Usuario entry (don't flush the Session after an exception occurs)
I found out the root of the problem. It is the next comparison:
obj.password != obj.confirmarPassword
If I write the following code inside the validator:
println "password: ${obj.password}"
println "confirmarPassword: ${obj.confirmarPassword)}"
Eclipse prints:
password: testPassword
confirmarPassword: testPassword
password: fd5cb51bafd60f6fdbedde6e62c473da6f247db271633e15919bab78a02ee9eb
confirmarPassword: testPassword
As my second attempt I tried:
if (obj.password != obj.springSecurityService.encodePassword(obj.confirmarPassword))
The validation doesn't pass:
Property [password] of class [class usuario.Usuario] with value [testPassword] does not pass custom validation
And with:
println "password: ${obj.password}"
println "confirmarPassword: ${obj.springSecurityService.encodePassword(obj.confirmarPassword)}"
Eclipse prints:
password: testPassword
confirmarPassword: fd5cb51bafd60f6fdbedde6e62c473da6f247db271633e15919bab78a02ee9eb
password: fd5cb51bafd60f6fdbedde6e62c473da6f247db271633e15919bab78a02ee9eb
confirmarPassword: fd5cb51bafd60f6fdbedde6e62c473da6f247db271633e15919bab78a02ee9eb
For my third attempt I tried:
if (obj.springSecurityService.encodePassword(obj.password) != obj.springSecurityService.encodePassword(obj.confirmarPassword))
Again the same error:
null id in usuario.Usuario entry (don't flush the Session after an exception occurs)
The password looks encrypted twice the second time:
password: fd5cb51bafd60f6fdbedde6e62c473da6f247db271633e15919bab78a02ee9eb
confirmarPassword: fd5cb51bafd60f6fdbedde6e62c473da6f247db271633e15919bab78a02ee9eb
password: e8c3cb111bf39f848b9a20e186f1663fd5acb0ae018ddf5763ae65bd6f45151e
confirmarPassword: fd5cb51bafd60f6fdbedde6e62c473da6f247db271633e15919bab78a02ee9eb
I'm running out of ideas. What about the client side? Would it be secure to perform this validation with Javascript?
This is my full domain class code:
package usuario
class Usuario implements Serializable {
transient springSecurityService
String username
String password
boolean enabled
boolean accountExpired
boolean accountLocked
boolean passwordExpired
String confirmarPassword
String nombre
String apellidos
String email
String telefono
String documentoIdentificacion
boolean aceptarPoliticaDeProteccionDeDatos = Boolean.FALSE
static transients = ['confirmarPassword', 'aceptarPoliticaDeProteccionDeDatos']
static constraints = {
username blank: false, unique: true
password blank: false, password: true
confirmarPassword bindable: true, blank:false, password: true, validator:{ val, obj ->
println "password: ${obj.password}"
println "confirmarPassword: ${val}"
if ((obj.password != val))
return 'usuario.password.dontmatch'
}
nombre blank: false
apellidos blank: false
email blank: false, email:true
telefono blank: false, matches: "[0-9 -+()]{3,15}"
documentoIdentificacion blank: false
aceptarPoliticaDeProteccionDeDatos bindable: true, validator:{ val, obj ->
if (!obj.id && obj.aceptarPoliticaDeProteccionDeDatos != true) //> !obj.id: si el usuario ya no está creado. Si ya está creado es que lo está modificando y no es necesario que vuelva a aceptar la política.
return 'usuario.politicaprotecciondatos.notaccepted'
}
}
static mapping = {
password column: '`password`'
}
Set<Rol> getAuthorities() {
UsuarioRol.findAllByUsuario(this).collect { it.rol } as Set
}
def beforeInsert() {
encodePassword()
}
def beforeUpdate() {
if (isDirty('password')) {
encodePassword()
}
}
protected void encodePassword() {
password = springSecurityService.encodePassword(password)
}
}
回答1:
If you are using spring security, you can try this:
class User{
String password
static mapping = {
password column: '`password`'
}
Set<Role> getAuthorities() {
UserRole.findAllByUser(this).collect { it.role } as Set
}
def beforeInsert() {
encodePassword()
}
def beforeUpdate() {
if (isDirty('password')) {
encodePassword()
}
}
protected void encodePassword() {
password = springSecurityService.encodePassword(password)
}
}
It will hep you to save encoded password in database.
You can make a command object take a variable password and encode password like this:
@Validateable
class CommandObject implements Serializable {
String password
String confirmPassword
static constraints = {
password nullable: false, blank: false
confirmPassword nullable: false, blank: false, validator: { val, object ->
if ((val != object.password)) {
return 'passwordMismatch'
}
return true
}
}
}
回答2:
Grails Spring Security Plugin encrypts your password before insert, but there is no need to invoke it unless you are actually comparing the current password to an old password. So a change password command object can have the following constraints:
static constraints = {
oldPassword validator: {val, obj ->
def actual = obj.springSecurityService.encodePassword(val)
if(actual != obj.secUser.password) 'old.password.must.match.current.password'
}
newPassword validator: {val, obj ->
if(val == obj.oldPassword) 'new.password.must.differ.from.old'
}
confirmPassword validator: {val, obj ->
if(val != obj.newPassword) 'confirm.password.must.match.new.password'
}
}
来源:https://stackoverflow.com/questions/18370593/spring-security-core-and-custom-validator-for-a-confirm-password-field-is-possib