简体   繁体   中英

spring-security-core custom authentication in grails

Iam using spring-security-core 2.0 RC5 in my grails application and I added an extra column in the user table named 'approved_fl' I just want check this flag while login, if this flag is P then i need to show a message like 'sorry your account is not yet approved by admin', if this flag is R then i need to show 'Sorry your account is rejected by admin'. How to configure my spring security plugin for this.

You will need to implement your own custom user details service in order to put that property on the user details (principal)

http://grails-plugins.github.io/grails-spring-security-core/v3/index.html#userDetailsService

Then you will need extend the org.springframework.security.authentication.AccountStatusUserDetailsChecker with your own implementation that checks the property on the user details.

You can register that implementation with a bean in resources.groovy like so:

userDetailsChecker(MyCustomUserDetailsChecker)

Then if you want to display a custom message to the user you will need to override the def authfail() { action of the LoginController to look for the exception you throw.

Finally I got this.

I done the following changes in my application.

In my resources.groovy

 import com.custom.auth.MyUserDetailsService import com.custom.auth.MyPreAuthenticationChecks beans = { preAuthenticationChecks(MyPreAuthenticationChecks) userDetailsService(MyUserDetailsService) } 

I created following groovy classes under src/groovy package

在此处输入图片说明

Here is the MyPreAuthenticationChecks.groovy

 package com.custom.auth import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.support.MessageSourceAccessor; import org.springframework.security.authentication.AccountExpiredException; import org.springframework.security.authentication.DisabledException; import org.springframework.security.authentication.LockedException; import org.springframework.security.core.SpringSecurityMessageSource; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsChecker; import com.custom.exception.AccountNotApprovedException import com.custom.exception.AccountRejectedException /** * Copy of the private class in AbstractUserDetailsAuthenticationProvider * to make subclassing or replacement easier. * * @author <a href='mailto:burt@burtbeckwith.com'>Burt Beckwith</a> */ public class MyPreAuthenticationChecks implements UserDetailsChecker { protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor(); protected final Logger log = LoggerFactory.getLogger(getClass()); public void check(UserDetails user) { if (!user.isAccountNonLocked()) { log.debug("User account is locked"); throw new LockedException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.locked", "User account is locked")); } if (!user.isEnabled()) { log.debug("User account is disabled"); throw new DisabledException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.disabled", "User is disabled")); } if (!user.isAccountNonExpired()) { log.debug("User account is expired"); throw new AccountExpiredException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.expired", "User account has expired")); } if (user.approveFl=='P') { log.debug("User account is not approved"); throw new AccountNotApprovedException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.notapproved", "User account not yet approved")); } if (user.approveFl=='R') { log.debug("User account is rejected"); throw new AccountRejectedException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.rejected", "User account has rejected")); } } } 

Here is the MyUserDetails.groovy

 package com.custom.auth import grails.plugin.springsecurity.userdetails.GrailsUser import org.springframework.security.core.GrantedAuthority class MyUserDetails extends GrailsUser { final char approveFl MyUserDetails(String username, String password, boolean enabled, boolean accountNonExpired, boolean credentialsNonExpired, boolean accountNonLocked, Collection<GrantedAuthority> authorities, long id, char approveFl) { super(username, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities, id) this.approveFl = approveFl } } 

Here is the MyUserDetailsService.groovy

 package com.custom.auth import com.domain.auth.User 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 (eg 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.approveFl) } } 

Here is the AccountNotApprovedException.groovy

 package com.custom.exception import org.springframework.security.core.AuthenticationException class AccountNotApprovedException extends AuthenticationException { public AccountNotApprovedException(String message, Throwable t) { super(message, t) } public AccountNotApprovedException(String message) { super(message) } public AccountNotApprovedException(String message, Object extraInformation) { super(message, extraInformation) } } 

Here is the AccountRejectedException.groovy

 package com.custom.exception import org.springframework.security.core.AuthenticationException class AccountRejectedException extends AuthenticationException { public AccountRejectedException(String message, Throwable t) { super(message, t) } public AccountRejectedException(String message) { super(message) } public AccountRejectedException(String message, Object extraInformation) { super(message, extraInformation) } } 

Simply copy your existing spring-security-core LoginController to groovy controller package (this will override the existing one)

Now update the authfail() of LoginController like follows

 def authfail() { String msg = '' def exception = session[WebAttributes.AUTHENTICATION_EXCEPTION] if (exception) { if (exception instanceof AccountExpiredException) { msg = message(code: 'springSecurity.errors.login.expired') } else if (exception instanceof CredentialsExpiredException) { msg = message(code: 'springSecurity.errors.login.passwordExpired') } else if (exception instanceof DisabledException) { msg = message(code: 'springSecurity.errors.login.disabled') } else if (exception instanceof LockedException) { msg = message(code: 'springSecurity.errors.login.locked') } else if (exception instanceof AccountNotApprovedException) { msg = g.message(code: "springSecurity.errors.login.notapproved") } else if (exception instanceof AccountRejectedException) { msg = g.message(code: "springSecurity.errors.login.rejected") } else if (exception instanceof SessionAuthenticationException){ msg = exception.getMessage() } else { msg = message(code: 'springSecurity.errors.login.fail') } } 

Now add the corresponding g:messages (which need to be shown when the exception will throw) to your spring-security-core.properties file

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM