Spring Security Core 和用于确认密码字段的自定义验证器是不是可行?

Posted

技术标签:

【中文标题】Spring Security Core 和用于确认密码字段的自定义验证器是不是可行?【英文标题】:Spring Security Core and custom validator for a confirm password field is possible?Spring Security Core 和用于确认密码字段的自定义验证器是否可行? 【发布时间】:2013-08-24 14:27:12 【问题描述】:

如果我写如下代码:

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']

passwordconfirmarPassword中引入相同的密码后出现如下错误:

usuario.Usuario 条目中的空 id(发生异常后不要刷新 Session)

我找到了问题的根源。这是下一个比较:

obj.password != obj.confirmarPassword

如果我在验证器中编写以下代码:

println "password: $obj.password"
println "confirmarPassword: $obj.confirmarPassword)"

Eclipse 打印:

password: testPassword
confirmarPassword: testPassword
password: fd5cb51bafd60f6fdbedde6e62c473da6f247db271633e15919bab78a02ee9eb
confirmarPassword: testPassword

作为我的第二次尝试,我尝试了:

if (obj.password != obj.springSecurityService.encodePassword(obj.confirmarPassword))

验证未通过:

具有值 [testPassword] 的类 [class usuario.Usuario] 的属性 [password] 未通过自定义验证

还有:

println "password: $obj.password"
println "confirmarPassword: $obj.springSecurityService.encodePassword(obj.confirmarPassword)"

Eclipse 打印:

password: testPassword
confirmarPassword: fd5cb51bafd60f6fdbedde6e62c473da6f247db271633e15919bab78a02ee9eb
password: fd5cb51bafd60f6fdbedde6e62c473da6f247db271633e15919bab78a02ee9eb
confirmarPassword: fd5cb51bafd60f6fdbedde6e62c473da6f247db271633e15919bab78a02ee9eb

我尝试了第三次尝试:

if (obj.springSecurityService.encodePassword(obj.password) != obj.springSecurityService.encodePassword(obj.confirmarPassword))

同样的错误:

usuario.Usuario 条目中的空 id(发生异常后不要刷新 Session)

密码第二次看起来加密了两次:

password: fd5cb51bafd60f6fdbedde6e62c473da6f247db271633e15919bab78a02ee9eb
confirmarPassword: fd5cb51bafd60f6fdbedde6e62c473da6f247db271633e15919bab78a02ee9eb
password: e8c3cb111bf39f848b9a20e186f1663fd5acb0ae018ddf5763ae65bd6f45151e
confirmarPassword: fd5cb51bafd60f6fdbedde6e62c473da6f247db271633e15919bab78a02ee9eb

我的想法已经不多了。客户端呢? 使用 Javascript 执行此验证是否安全?

这是我的完整域类代码:

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)
    

【问题讨论】:

val 中的validator 真的是旁观者吗?? "usuario.Usuario 条目中的空 id" -> 您的域类 id 已分配并且为空?可以完全共享域类吗? 我不明白你对 spectator @dmahapatro 是什么意思。 @sérgio,我很确定错误是因为一个非空字段在尝试存储在数据库中时为空。它通过java代码中的验证器,但它没有通过数据库中的验证器?这不是 here 发布的错误(正如我一开始所想的那样)。 我发布了完整的域类@SérgioMichels 谢谢你所做的一切:) 【参考方案1】:

如果你使用的是spring security,可以试试这个:

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)
 

它将帮助您将编码的密码保存在数据库中。

您可以使命令对象采用可变密码并对密码进行编码,如下所示:

@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
            
 

【讨论】:

我将验证器从密码移到了确认密码,并将obj.password != obj.confirmarPassword 更改为obj.password != val(因为这些是我在代码中看到的唯一区别)。结果与尝试1相同:( 我不能接受作为答案,因为它不适用于我的情况。我认为这是因为confirmPassword 在我的情况下是瞬态的,因为我不想将它存储在数据库中。 我也没有在我的数据库中存储确认密码。我只是在命令对象中比较它,并且只在数据库中保存密码。或者您想说您不想将密码保存在数据库中。 今天下午给我时间研究一下命令对象是什么:) 不,我们只是相差 3 小时 30 分钟。我想晚上在你身边。【参考方案2】:

Grails Spring Security Plugin 在insert 之前加密您的密码,但除非您实际将当前密码与旧密码进行比较,否则无需调用它。所以修改密码命令对象可以有以下约束:

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'
    

【讨论】:

谢谢。这个答案肯定对我将来有用。但这并不能解决当前的问题:/

以上是关于Spring Security Core 和用于确认密码字段的自定义验证器是不是可行?的主要内容,如果未能解决你的问题,请参考以下文章

Grails + spring-security-core:用户登录后如何分配角色?

Grails - 卸载 Spring Security Core

Grails Spring Security Core 创建新用户

如何使用 grails 1.3.2 和插件 spring-security-core 1 实现自定义 FilterSecurityInterceptor?

spring security core 安全自定义 url

Spring Security 接口认证鉴权入门实践指南