Today we’ll talk about the ways to filter user access to some controllers and actions in the Grails application. There are 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 on the solutions that are suggested by
spring security plugin. One of them is an @Secured annotation. You may
use it on the class or action level. Here is an example of using
@Secured on different levels:
1
2
3
4
5
6
7
8
9
10
11
@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 has access to this
controller, and only super admin has access to the superAdmin action. In
some cases there is a lot more convenient to specify a list of
controllers and actions to which specified users has access to. This
could be done by using an intercept URLs map in config.groovy file. Here
is an example of using it.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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, rights
that was specified first has greater priority.
Sure this is a great solutions, but what would you do if using of
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, with interceptors
you may 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 interceptor that will be executed before every action write
the following code:
1
2
3
4
5
class SampleController {
def beforeInterceptor = {
//do something
}
}
Let's look at the example, that will show how to make interceptor
execute only for specified actions.
1
2
3
4
5
//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']]
AfterInterceptors are being executed after the action, so they could
modify model and modelAndView objects and could be used as follows:
1
2
3
4
5
def afterInterceptor = { model, modelAndView ->
if(model.changeView) {
modelAndView.viewName = "/samplecontroller/otherview"
}
}
If we are dealing with application that has really big amount of
controllers using of interceptors is not so convenient, in this case
using of 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, afterView - executed after rendering the view. Here is an
example of applying different filters.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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
}
}
}
}
}