Grails MongoDB脏检查在Spring Security中失败

Grails MongoDB脏检查在Spring Security中失败,grails,gorm,gorm-mongodb,grails-spring-security,Grails,Gorm,Gorm Mongodb,Grails Spring Security,我将Grails3.3.2与mongoDB插件(v6.1.4)和SpringSecurity核心插件(v3.2.0)一起使用 我有以下UserPasswordEncoderListener和以下persistenceEvent方法: @Override protected void onPersistenceEvent(AbstractPersistenceEvent event) { if (event.entityObject instanceof User) {

我将Grails3.3.2与mongoDB插件(v6.1.4)和SpringSecurity核心插件(v3.2.0)一起使用

我有以下
UserPasswordEncoderListener
和以下persistenceEvent方法:

 @Override
protected void onPersistenceEvent(AbstractPersistenceEvent event) {
    if (event.entityObject instanceof User) {
        User u = (event.entityObject as User)
        if (u.password && (event.eventType == EventType.PreInsert || (event.eventType == EventType.PreUpdate && u.hasChanged('password')))) {
            event.getEntityAccess().setProperty("password", encodePassword(u.password))
        }
    }
}
问题在于每次保存未更新的用户对象时,
hasChanged
调用总是返回true,从而导致已编码密码被重新编码,从而破坏身份验证

一种解决方法是使用旧方法,只需从数据库中检索原始密码,并在编码之前进行比较,但我想知道为什么
hasChanged
会错误地返回true

通过在groovy控制台中运行以下命令,我测试了
hasChanged
在其他地方的行为是否正确:

def user = User.findByEmail("user@email.com")
println "Result: "+ user.hasChanged('password')
结果是
result:false
。 为什么它在持久性侦听器类中不起作用

仅供参考:我在resources.groovy中定义了以下bean:

userPasswordEncoderListener(UserPasswordEncoderListener,ref('mongoDatastore'))

目前的临时解决方案:

@Override
protected void onPersistenceEvent(AbstractPersistenceEvent event) {
    if (event.entityObject instanceof User) {
        User u = (event.entityObject as User)
        if (u.password && (event.eventType == EventType.PreInsert || (event.eventType == EventType.PreUpdate && u.hasChanged('password')))) {
            if(event.eventType == EventType.PreUpdate){ //Temp workaround until hasChanged behaves correctly
                def originalUser = User.get(u?.id)
                if(originalUser.password != u.password){
                    event.getEntityAccess().setProperty("password", encodePassword(u.password))
                }
            }else {
                event.getEntityAccess().setProperty("password", encodePassword(u.password))
            }

        }
    }
}

在github repo()上留下了一个问题。将随反馈更新。

您是否尝试在侦听器中使用
isDirty()
而不是
hasChanged()

例如:

package com.mycompany.myapp

import grails.plugin.springsecurity.SpringSecurityService
import org.grails.datastore.mapping.engine.event.AbstractPersistenceEvent
import org.grails.datastore.mapping.engine.event.PreInsertEvent
import org.grails.datastore.mapping.engine.event.PreUpdateEvent
import org.springframework.beans.factory.annotation.Autowired
import grails.events.annotation.gorm.Listener
import groovy.transform.CompileStatic

@CompileStatic
class UserPasswordEncoderListener {

    @Autowired
    SpringSecurityService springSecurityService

    @Listener(User)
    void onPreInsertEvent(PreInsertEvent event) {
        encodePasswordForEvent(event)
    }

    @Listener(User)
    void onPreUpdateEvent(PreUpdateEvent event) {
        encodePasswordForEvent(event)
    }

    private void encodePasswordForEvent(AbstractPersistenceEvent event) {
        if (event.entityObject instanceof User) {
            User u = event.entityObject as User
            if (u.password && ((event instanceof  PreInsertEvent) || (event instanceof PreUpdateEvent && u.isDirty('password')))) {
                event.getEntityAccess().setProperty('password', encodePassword(u.password))
            }
        }
    }

    private String encodePassword(String password) {
        springSecurityService?.passwordEncoder ? springSecurityService.encodePassword(password) : password
    }
}
有关更多信息,请访问: