Grails Spring Security Core Plugin – Registering Callback Closures
I was searching for a way to hook business logic after successful user login while using Spring Security Core plugin. The simplest way to do this is to register callback closures. It let’s you hook your custom code inside Config.groovy after certain Spring Security events.
If you are unfamiliar with this plugin, visit the previous tutorial on Spring Security Core Plugin.
Registering Callback Closures
When you want to hook business logic on certain Spring Security Core events, you can edit grails-app/conf/Config.groovy and add something like the following:
grails.plugins.springsecurity.useSecurityEventListener = true grails.plugins.springsecurity. onInteractiveAuthenticationSuccessEvent = { e, appCtx -> // add custom code here } grails.plugins.springsecurity. onAbstractAuthenticationFailureEvent = { e, appCtx -> // add custom code here } grails.plugins.springsecurity. onAuthenticationSuccessEvent = { e, appCtx -> // add custom code here } grails.plugins.springsecurity. onAuthenticationSwitchUserEvent = { e, appCtx -> // add custom code here } grails.plugins.springsecurity. onAuthorizationEvent = { e, appCtx -> // add custom code here }
When using this, it is important to set grails.plugins.springsecurity.useSecurityEventListener to true as shown in the first line above.
As per the documentation in the plugin docs:
- When a user authenticates, Spring Security initially fires an AuthenticationSuccessEvent (onAuthenticationSuccessEvent callback). This event fires before the Authentication is registered in the SecurityContextHolder, which means that the springSecurityService methods that access the logged-in user will not work.
- Later in the processing a second event is fired, an InteractiveAuthenticationSuccessEvent (onInteractiveAuthenticationSuccessEvent callback), and when this happens the SecurityContextHolder will have the Authentication.
- This means if you don’t need to retrieve the logged in user, you can hook to onAuthenticationSuccessEvent. Otherwise, hook with onInteractiveAuthenticationSuccessEvent.
Example
This example will log all successful logins to a database table.
Model
I assume that the model for the user is SecUser as discussed here.
The logs will be saved in SecUserLog data model.
class SecUserLog { String username String action static constraints = { username blank: false, nullable: false action blank: false, nullable: false } }
Service
I created a service to wrap all business logic to the SecUserLog domain. I used a service to show later how to access this inside Config.groovy.
class SecUserLogService { static transactional = true def securityService def addUserLog(String action) { SysUser user = securityService.getLoggedUser() SysUserActionLog log = new SysUserActionLog(username:user.username, action:action) log.save() } }
Note that the service securityService is from the Spring Security Core Plugin.
Config.groovy entries
This is the code I added in Config.groovy:
grails.plugins.springsecurity.useSecurityEventListener = true grails.plugins.springsecurity.onInteractiveAuthenticationSuccessEvent = { e, appCtx -> def secUserLogService = appCtx.getBean('secUserLogService') secUserLogService.addUserLog("login") }
The appCtx object is the application context, which can be used to look up Spring managed beans – that includes the services. After that, you can use the service as you please.
Reference: | Grails Spring Security Core Plugin – Registering Callback Closures from our JCG partner Jonathan Tan at the Grails cookbook blog. |