Spring Security Core Plugin 七(自定义UserDetailsService)

当使用DaoAuthenticationProvider从数据库中验证用户时,需要实现UserDetailsService和UserDetails,插件提供了grails.plugin.springsecurity.userdetails.GormUserDetailService作为UserDetailsService的实现类,grails.plugin.springsecurity.userdetails.GrailsUser作为UserDetails的实现类。

可以扩展或替换GormUserDetailsService,需要在grails-app/conf/spring/resources.groovy使用相同的名字userDetailsService,这是因为应用bean的配置是在插件的bean之后,而同一个名字的bean只能有一个。自定义的类需要写在src/groovy下,而不是grails-app/services下,这是为了保证一致性。

package com.mycompany.myapp

import grails.plugin.springsecurity.userdetails.GrailsUser
import org.springframework.security.core.GrantedAuthority

class MyUserDetails extends GrailsUser {

   final String fullName

   MyUserDetails(String username, String password, boolean enabled,
                 boolean accountNonExpired, boolean credentialsNonExpired,
                 boolean accountNonLocked,
                 Collection authorities,
                 long id, String fullName) {
      super(username, password, enabled, accountNonExpired,
            credentialsNonExpired, accountNonLocked, authorities, id)

      this.fullName = fullName
   }
}
package com.mycompany.myapp

import grails.plugin.springsecurity.SpringSecurityUtils
import grails.plugin.springsecurity.userdetails.GrailsUserDetailsService
import grails.plugin.springsecurity.userdetails.NoStackUsernameNotFoundException
import grails.transaction.Transactional
import org.springframework.security.core.authority.SimpleGrantedAuthority
import org.springframework.security.core.userdetails.UserDetails
import org.springframework.security.core.userdetails.UsernameNotFoundException

class MyUserDetailsService implements GrailsUserDetailsService {

   /**
    * Some Spring Security classes (e.g. RoleHierarchyVoter) expect at least
    * one role, so we give a user with no granted roles this one which gets
    * past that restriction but doesn't grant anything.
    */
   static final List NO_ROLES = [new SimpleGrantedAuthority(SpringSecurityUtils.NO_ROLE)]

   UserDetails loadUserByUsername(String username, boolean loadRoles)
         throws UsernameNotFoundException {
      return loadUserByUsername(username)
   }

   @Transactional(readOnly=true, noRollbackFor=[IllegalArgumentException, UsernameNotFoundException])
   UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

      User user = User.findByUsername(username)
      if (!user) throw new NoStackUsernameNotFoundException()

      def roles = user.authorities

      // or if you are using role groups:
      // def roles = user.authorities.collect { it.authorities }.flatten().unique()

      def authorities = roles.collect {
         new SimpleGrantedAuthority(it.authority)
      }

      return new MyUserDetails(user.username, user.password, user.enabled,
            !user.accountExpired, !user.passwordExpired,
            !user.accountLocked, authorities ?: NO_ROLES, user.id,
            user.firstName + " " + user.lastName)
   }
}
The loadUserByUsername method is transactional, but read-only, to avoid lazy loading exceptions when accessing the authorities collection. There are obviously no database updates here but this is a convenient way to keep the Hibernate Session open to enable accessing the roles.

To use your implementation, register it in grails-app/conf/spring/resources.groovy like this:

Listing 58. Registering a custom UserDetailsService in resources.groovy
import com.mycompany.myapp.MyUserDetailsService

beans = {
   userDetailsService(MyUserDetailsService)
}

刷新缓存的验证信息

如果在自定义的UserDetails中保存了易变的数据,在数据变化时需要重建Authentication。

class MyController {

   def springSecurityService

   def someAction() {
      def user = ...
      // update user data
      user.save()
      springSecurityService.reauthenticate user.username
      ...
   }
}

 

最后欢迎大家访问我的个人网站:1024s​​​​​​​

 

你可能感兴趣的:(秒扒Spring)