【问题标题】:grails spring security acl query exceptiongrails spring security acl查询异常
【发布时间】:2013-07-04 19:33:07
【问题描述】:

我正在尝试使用 spring security acl 对用户的电子邮件地址进行身份验证。我想使用属于 User 域对象的 accountPerson 的电子邮件地址。当我保存用户时,一切正常并且我的数据库正确更新,但是当我尝试进行身份验证时,我得到一个hibernate.QueryException: could not resolve property: accountPerson.email of: com.loggyt.User 这是代码和错误消息。任何帮助将不胜感激。谢谢

AccountPerson.groovy

class AccountPerson implements Serializable{

String firstName
String lastName
Address address
String email
String primaryPhone
String secondaryPhone

static belongsTo = [user:User]

static mapping = {
    address cascade: 'all'
}

Date dateCreated
Date lastUpdated

static constraints = {
    firstName nullable: false, blank: false
    lastName  nullable: false, blank: false
    address nullable: true
    primaryPhone blank: false, nullable: false
    secondaryPhone blank: true, nullable: true
    email nullable: false, blank: false, email: true, unique: true
}
}

User.groovy:

import java.util.Date

class User implements Serializable{

transient springSecurityService

transient String password

boolean enabled
boolean accountExpired
boolean accountLocked
boolean passwordExpired

Date dateCreated
Date lastUpdated

static hasOne = [accountPerson: AccountPerson]

static constraints = {
    password blank: false
    accountPerson bindable: true
    password bindable: true
}

static mapping = {
    password column: '`password`'
    accountPerson fetch: 'join'
}

Set<Role> getAuthorities() {
    UserRole.findAllByUser(this).collect { it.role } as Set
}

void beforeInsert() {
    encodePassword()
}

void beforeUpdate() {
    if (isDirty('password')) {
        encodePassword()
    }
}

/**
 * After this user has been updated to the database, log the user back in
 * using the new credentials.
 */
void afterUpdate() {
    this.discard()
    this.springSecurityService.reauthenticate(person.email)
}


/**
 * Get a user based on its email address.
 *
 * @param email email of a user
 * @return the user that has the email parameter
 */
static User findByEmail(String email){
    User.createCriteria().get{
        accountPerson{
            eq('email', email)
        }
    }
}

protected void encodePassword() {
    password = this.springSecurityService.encodePassword(password)
}
}

配置

// Added by the Spring Security Core plugin:
grails.plugins.springsecurity.userLookup.userDomainClassName = 'com.loggyt.User'
grails.plugins.springsecurity.userLookup.usernamePropertyName = 'accountPerson.email'
grails.plugins.springsecurity.userLookup.passwordPropertyName = 'password'
grails.plugins.springsecurity.userLookup.authorityJoinClassName = 'com.loggyt.UserRole'
grails.plugins.springsecurity.authority.className = 'com.loggyt.Role'

引导带

    def dbCreate = grailsApplication.config.dataSource.dbCreate
    if(dbCreate == "create" || dbCreate == "create-drop"){

        /**
         * Create Roles. 
         * 
         */
        def adminRole = new Role(authority: 'ROLE_ADMIN').save(flush:true)
        def userRole = new Role(authority: 'ROLE_USER').save(flush:true)

        def person = new AccountPerson(
            firstName: 'Otto',
            lastName: 'Admin',
            email: "noreply@loggyt.com",
            primaryPhone: "555-555-5555")

        def user = new User (enabled: true, password: "password")
        user.accountPerson = person
        user.save(flush:true)

        UserRole.create user, adminRole, true

        person = new AccountPerson(
            firstName: 'Normal',
            lastName: 'User',
            email: "user@loggyt.com",
            primaryPhone: "555-555-5555")

        user = new User (enabled: true, password: "password")
        user.accountPerson = person
        user.save(flush:true)

        UserRole.create user, userRole, true

        assert User.count() == 2
        assert Role.count() == 2
        assert UserRole.count() == 2
    }
}

log4j 调试消息

2013-07-07 00:57:33,088 [http-bio-8443-exec-3] DEBUG authentication.ProviderManager  - Authentication attempt using org.springframework.security.authentication.dao.DaoAuthenticationProvider
2013-07-07 00:57:33,138 [http-bio-8443-exec-3] DEBUG datasource.DataSourceUtils  - Fetching JDBC Connection from DataSource
2013-07-07 00:57:33,162 [http-bio-8443-exec-3] DEBUG support.TransactionTemplate  - Initiating transaction rollback on application exception
Message: could not resolve property: accountPerson.email of: com.loggyt.User; nested exception is org.hibernate.QueryException: could not resolve property: accountPerson.email of: com.loggyt.User
    Line | Method
->>  592 | findWhere       in org.grails.datastore.gorm.GormStaticApi
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|    686 | withTransaction in     ''
|   1110 | runWorker . . . in java.util.concurrent.ThreadPoolExecutor
|    603 | run             in java.util.concurrent.ThreadPoolExecutor$Worker
^    722 | run . . . . . . in java.lang.Thread

Caused by QueryException: could not resolve property: accountPerson.email of: com.loggyt.User
->>  592 | findWhere       in org.grails.datastore.gorm.GormStaticApi
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|    686 | withTransaction in     ''
|   1110 | runWorker . . . in java.util.concurrent.ThreadPoolExecutor
|    603 | run             in java.util.concurrent.ThreadPoolExecutor$Worker
^    722 | run . . . . . . in java.lang.Thread

【问题讨论】:

    标签: authentication grails spring-security hibernate-mapping


    【解决方案1】:

    我相信默认的 UserDetailsS​​ervice 会根据用户名查找用户,因此除了您已配置的内容之外,您还需要创建自定义 UserDetailsS​​ervice 并实现 loadUserByUsername 方法。这是一个简单的例子:

    class CustomUserDetailsService implements GrailsUserDetailsService {
    
      UserDetails loadUserByUsername(String username, boolean loadRoles)
    throws UsernameNotFoundException {
      return loadUserByUsername(username)
      }
    
      UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
    
        User.withTransaction { status ->
          User user = User.findByEmail(username)
    
          if (!user) {
            throw new UsernameNotFoundException('User not found', username)
          }
    
          def authorities = user.authorities.collect {
            new GrantedAuthorityImpl(it.authority)
          }
    
          return new GrailsUser(user.username, user.password, 
             user.enabled, !user.accountExpired, 
             !user.passwordExpired, !user.accountLocked, 
             authorities ?: NO_ROLES, user.id
          )
        }
      }
    }
    

    然后在 conf/spring/resources.groovy 中通知 Grails 你的新 UserDetailsS​​ervice 实现

    beans = {
      userDetailsService(com.loggyt.CustomUserDetailsService)
    }
    

    【讨论】:

    • 太棒了,这正是我所需要的。我在return new GrailsUser 语句中将user.username 更改为user.person.email,它非常有效,谢谢。
    • 抱歉,更改为user.accountPerson.email 以进行澄清。再次感谢您。
    猜你喜欢
    • 2014-11-21
    • 2014-05-07
    • 1970-01-01
    • 2019-07-18
    • 2014-02-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-19
    相关资源
    最近更新 更多