0

I am trying to authenticate a user with their email address using spring security acl. I want to use the email address of an accountPerson which belongs to the User domain object. When I save the user everything works fine and my database updates correctly but when I try to authenticate I get a hibernate.QueryException: could not resolve property: accountPerson.email of: com.loggyt.User Here is the code and error messages. Any help will be greatly appreciated. Thanks

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)
}
}

Config

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

BootStrap

    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 Debug Message

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
4

1 回答 1

0

我相信默认的 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)
}
于 2013-07-07T10:08:06.647 回答