Grails MongoDB 脏检查因 Spring 安全性而失败
Grails MongoDB Dirty Checking Fails With Spring Security
我正在使用带有 mongoDB 插件 (v6.1.4) 和 Spring 安全核心插件 (v3.2.0) 的 Grails 3.3.2。
我有以下 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
调用总是 return true 导致已经编码的密码是重新编码,从而破坏身份验证。
一种解决方法是按照旧方法进行,只需从数据库中检索原始密码并在编码前比较它们,但我想知道为什么 hasChanged
错误地 return 为真。
我通过 运行 在 groovy 控制台中的以下内容测试了 hasChanged
在其他地方的行为是否正确:
def user = User.findByEmail("user@email.com")
println "Result: "+ user.hasChanged('password')
结果是Result: false
。
为什么它在持久性侦听器 class 中不起作用?
仅供参考: 我在 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 回购 (https://github.com/grails-plugins/grails-spring-security-core/issues/539) 上留下了一个问题。将根据反馈进行更新。
您是否尝试过在监听器中使用 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
}
}
更多信息请访问:https://grails-plugins.github.io/grails-spring-security-core/3.2.x/index.html#tutorials
我正在使用带有 mongoDB 插件 (v6.1.4) 和 Spring 安全核心插件 (v3.2.0) 的 Grails 3.3.2。
我有以下 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
调用总是 return true 导致已经编码的密码是重新编码,从而破坏身份验证。
一种解决方法是按照旧方法进行,只需从数据库中检索原始密码并在编码前比较它们,但我想知道为什么 hasChanged
错误地 return 为真。
我通过 运行 在 groovy 控制台中的以下内容测试了 hasChanged
在其他地方的行为是否正确:
def user = User.findByEmail("user@email.com")
println "Result: "+ user.hasChanged('password')
结果是Result: false
。
为什么它在持久性侦听器 class 中不起作用?
仅供参考: 我在 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 回购 (https://github.com/grails-plugins/grails-spring-security-core/issues/539) 上留下了一个问题。将根据反馈进行更新。
您是否尝试过在监听器中使用 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
}
}
更多信息请访问:https://grails-plugins.github.io/grails-spring-security-core/3.2.x/index.html#tutorials