当使用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