Today, we’ll talk about the ways to filter user access to some controllers and actions in the Grails application. There are a few solutions that could be really useful for implementing this task. So let’s look at a quick overview of them.
At first, let’s take a look at the solutions that are suggested by the Spring Security plugin. One of them is an @Secured annotation. You may use it at the class or action level. Here is an example of using @Secured on different levels:
@Secured([‘ROLE_ADMIN’, ‘ROLE_SUPER_ADMIN’])
class AdminController {
def index = {
render ‘you have admin rights’
}
@Secured([‘ROLE_SUPER_ADMIN’])
def superAdmin = {
render ‘you have super admin rights’
}
}In this example, users with admin or super admin roles have access to this controller, and only super admins have access to the superAdmin action. In some cases, it is a lot more convenient to specify a list of controllers and actions to which specified users have access. This could be done by using an intercept URLs map in config.groovy file. Here is an example of using it.
import grails.plugins.springsecurity.SecurityConfigType
import org.codehaus.groovy.grails.plugins.springsecurity.SpringSecurityUtils
…
//specifying security config type
grails.plugins.springsecurity.securityConfigType=SecurityConfigType.InterceptUrlMap
//defining the user class name
grails.plugins.springsecurity.userLookup.userDomainClassName = 'sysgears.User'
//defining authority join class name
// UserSecRole - collection that contains user - security role relation
grails.plugins.springsecurity.userLookup.authorityJoinClassName = 'sysgears.UserSecRole'
//defining security role class name
grails.plugins.springsecurity.authority.className = 'sysgears.SecRole'
//map to secure URLs
grails.plugins.springsecurity.interceptUrlMap = [
'/': ['IS_AUTHENTICATED_ANONYMOUSLY'],
'/login/**': ['IS_AUTHENTICATED_ANONYMOUSLY'],
'/register/**': ['IS_AUTHENTICATED_ANONYMOUSLY'],
'/images/**': ['IS_AUTHENTICATED_ANONYMOUSLY'],
'/css/**': ['IS_AUTHENTICATED_ANONYMOUSLY'],
'/fonts/**': ['IS_AUTHENTICATED_ANONYMOUSLY'],
'/js/**': ['IS_AUTHENTICATED_ANONYMOUSLY'],
'admin/superAdmin/**':['ROLE_SUPER_ADMIN'],
'admin/**':['ROLE_ADMIN', 'ROLE_SUPER_ADMIN']
]Please make sure that you specified the right order of mapping; the rights that were specified first have greater priority. Sure, this is a great solution, but what would you do if using security roles is not enough for you? In this case, standard Grails features, such as interceptors and filters, could be really useful. At first, let’s talk about interceptors. Interceptor is a nice tool not only to filter user access to some controllers and actions, but also to modify the data that’s being received and sent by actions, change the view that should be rendered after executing, and more. There are two kinds of interceptors: beforeInterceptor and afterInterceptor. To define an interceptor that will be executed before every action, write the following code:
class SampleController {
def beforeInterceptor = {
//do something
}
}Let’s look at the example that will show how to make the interceptor execute only for specified actions.
//interceptor will be executed for all the actions except 'register' and 'login'
//auth is an action that will be executed as interceptor
def beforeInterceptor = [action:this.&auth,except:['login', 'register']]
//interceptor will be executed only for 'superAdmin' action
def beforeInterceptor = [action:this.&auth,only:['superAdmin']]After interceptors execute after the action but before view rendering, so they can modify model and modelAndView objects. Here’s how to use them:
def afterInterceptor = { model, modelAndView ->
if(model.changeView) {
modelAndView.viewName = "/samplecontroller/otherview"
}
}If we are dealing with an application that has a really large number of controllers, using interceptors is not so convenient; in this case, using filters could be a better solution. To create a filter, create a class that ends with the convention Filters in the grails-app/conf directory. Within this class, define a code block called filters that contains the filter definitions. Within the filters, there are three types of interceptors: before – executed before action, after – executed after action, and afterView – executed after rendering the view. Here is an example of applying different filters.
class BlockFilters {
def filters = {
//applies filter to all the controllers
allTabsFilter(controller: '*', action: '*') {
before {
//do something
}
}
//applies filter to some controller
vipFilter(controller: 'vip', action: '*') {
before {
//do something
}
}
//applies filter to all controllers except 'Login', 'Logout',
//'Register' and 'Ban'
banFilter(controller: '(login|logout|ban|register)',
action: '*', invert:true) {
before = {
User user = User.findByUsername(applicationContext.
getBean("springSecurityService").authentication.name)
if (user && user.isBanned()) {
redirect(controller: "ban", action: "index")
return false
}
}
}
}
}
