Grails中的错误:在刷新之前保存临时实例
在使用spring security和LDAP的Grails应用程序中运行用户身份验证时,我遇到了一个问题 到LDAP的连接工作正常,我得到了结果。但是,我没有得到管理,用户可以登录,数据保存在本地数据库中 我已更改/创建以下文件: config.groovyGrails中的错误:在刷新之前保存临时实例,grails,groovy,spring-security,spring-security-ldap,Grails,Groovy,Spring Security,Spring Security Ldap,在使用spring security和LDAP的Grails应用程序中运行用户身份验证时,我遇到了一个问题 到LDAP的连接工作正常,我得到了结果。但是,我没有得到管理,用户可以登录,数据保存在本地数据库中 我已更改/创建以下文件: config.groovy grails.plugin.springsecurity.ldap. context.managerDn = 'USERNAME' grails.plugin.springsecurity.ldap. context.managerPas
grails.plugin.springsecurity.ldap. context.managerDn = 'USERNAME'
grails.plugin.springsecurity.ldap. context.managerPassword = 'PASSWORD'
grails.plugin.springsecurity.ldap. context.server ='ldap://LDAPSERVER:389/'
grails.plugin.springsecurity.ldap. authorities.ignorePartialResultException = true // typically needed for Active Directory
grails.plugin.springsecurity.ldap. search.base = 'DC=example,DC=com'
grails.plugin.springsecurity.ldap. search.filter='(sAMAccountName={0})' // for Active Directory you need this
grails.plugin.springsecurity.ldap. search.searchSubtree = true
grails.plugin.springsecurity.ldap.authorities.groupSearchBase ='DC=example,DC=com'
grails.plugin.springsecurity.ldap.authorities.groupSearchFilter = 'member={0}'
grails.plugin.springsecurity.ldap.authorities.retrieveDatabaseRoles = false
grails.plugin.springsecurity.ldap. auth.hideUserNotFoundExceptions = false
grails.plugin.springsecurity.ldap. search.attributesToReturn = ['mail', 'displayName', 'title', 'fullname'] // extra attributes you want returned; see below for custom classes that access this data
grails.plugin.springsecurity.providerNames = ['ldapAuthProvider']
grails.plugin.springsecurity.ldap.useRememberMe = false
grails.plugin.springsecurity.ldap.authorities.defaultRole = 'ROLE_USER'
grails.plugin.springsecurity.ldap.mapper.userDetailsClass = 'CustomUserDetails'
src/grovvy/CustomUserDetailsMapper.grovvy
package com.example
import com.example.CustomUserDetails
import org.springframework.ldap.core.DirContextAdapter
import org.springframework.ldap.core.DirContextOperations
import org.springframework.security.core.userdetails.UserDetails
import org.springframework.security.ldap.userdetails.UserDetailsContextMapper
import groovy.sql.Sql
import org.springframework.security.core.userdetails.UserDetails
import org.springframework.security.ldap.userdetails.UserDetailsContextMapper
import org.springframework.security.core.authority.SimpleGrantedAuthority
import org.springframework.security.core.GrantedAuthority
import org.springframework.security.core.userdetails.UsernameNotFoundException
import org.springframework.security.authentication.DisabledException
class CustomUserDetailsContextMapper implements UserDetailsContextMapper {
private static final List NO_ROLES = [new SimpleGrantedAuthority("ROLE_USER")]
def dataSource
@Override
public CustomUserDetails mapUserFromContext(DirContextOperations ctx, String username, Collection<GrantedAuthority> authority) {
username = username.toLowerCase()
User.withTransaction {
User user = User.findByUsername(username)
String firstName = ctx.originalAttrs.attrs['givenname'].values[0]
String lastName = ctx.originalAttrs.attrs['sn'].values[0]
def roles
if(!user){
user = new User(username: username, enabled: true, firstName: firstName, lastName: lastName)
user.save(flush: true)
}
else {
user = User.findByUsername(username)
user.firstName = firstName
user.lastName = lastName
user.save(flush)
}
roles = user.getAuthorities()
}
if( !user.enabled )
throw new DisabledException("User is disabled", username)
def authorities = roles.collect { new SimpleGrantedAuthority(it.authority) }
authorities.addAll(authority)
def userDetails = new CustomUserDetails(username, user.password, user.enabled, false, false, false, authorities, user.id, user.firstName, user.lastName)
return userDetails
}
@Override
public void mapUserToContext(UserDetails arg0, DirContextAdapter arg1) {
}
}
user = new User(username: username, enabled: true, firstName: firstName, lastName: lastName)
conf/resources.groovy
// Place your Spring DSL code here
import com.example.CustomUserDetailsContextMapper
import com.example.CustomUserDetailsService
beans = {
userDetailsService(CustomUserDetailsService)
ldapUserDetailsMapper(CustomUserDetailsContextMapper) {
dataSource = ref("dataSource")
}
}
使用此配置运行并尝试登录时,会收到以下错误消息:
Message: object references an unsaved transient instance - save the transient instance before flushing: com.example.User; nested exception is org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: com.example.User
我也有同样的问题。错误消息表示未保存用户实例。我通过更改CustomUserDetailsMapper.grovvvy中的以下行修复了它
package com.example
import com.example.CustomUserDetails
import org.springframework.ldap.core.DirContextAdapter
import org.springframework.ldap.core.DirContextOperations
import org.springframework.security.core.userdetails.UserDetails
import org.springframework.security.ldap.userdetails.UserDetailsContextMapper
import groovy.sql.Sql
import org.springframework.security.core.userdetails.UserDetails
import org.springframework.security.ldap.userdetails.UserDetailsContextMapper
import org.springframework.security.core.authority.SimpleGrantedAuthority
import org.springframework.security.core.GrantedAuthority
import org.springframework.security.core.userdetails.UsernameNotFoundException
import org.springframework.security.authentication.DisabledException
class CustomUserDetailsContextMapper implements UserDetailsContextMapper {
private static final List NO_ROLES = [new SimpleGrantedAuthority("ROLE_USER")]
def dataSource
@Override
public CustomUserDetails mapUserFromContext(DirContextOperations ctx, String username, Collection<GrantedAuthority> authority) {
username = username.toLowerCase()
User.withTransaction {
User user = User.findByUsername(username)
String firstName = ctx.originalAttrs.attrs['givenname'].values[0]
String lastName = ctx.originalAttrs.attrs['sn'].values[0]
def roles
if(!user){
user = new User(username: username, enabled: true, firstName: firstName, lastName: lastName)
user.save(flush: true)
}
else {
user = User.findByUsername(username)
user.firstName = firstName
user.lastName = lastName
user.save(flush)
}
roles = user.getAuthorities()
}
if( !user.enabled )
throw new DisabledException("User is disabled", username)
def authorities = roles.collect { new SimpleGrantedAuthority(it.authority) }
authorities.addAll(authority)
def userDetails = new CustomUserDetails(username, user.password, user.enabled, false, false, false, authorities, user.id, user.firstName, user.lastName)
return userDetails
}
@Override
public void mapUserToContext(UserDetails arg0, DirContextAdapter arg1) {
}
}
user = new User(username: username, enabled: true, firstName: firstName, lastName: lastName)
到
并通过向用户域类添加firstName和lastName
正如您所看到的,我刚刚向用户添加了一些默认值,这应该是创建的。密码始终设置为“测试”并不重要。它不会被使用,因为您正在使用LDAP。对于那些修改了从spring security生成的用户类(在运行quickstart脚本之后)并收到相同错误的人,我已将域用户类中的
静态约束
中的nullable:true
添加到所有自定义属性中—在本例中为firstName和lastName。这允许您保存实例,而无需显式设置所有属性
希望这对别人有帮助
静态约束={
用户名空白:false,唯一:true
密码空白:false
fname可为空:true
lname可为空:true
}
user = new User(username: username, enabled: true, firstName: firstName, lastName: lastName, accountLocked: false, passwordExpired: false, accountExpired: false, password: "test")