mengu on web programming.

Annotating Your Grails Controller Classes And Actions

For the current project of mine which I'm building with Grails I needed to annotate my controller classes and some actions in some cases. I had no idea on how to do it but I think I have just solved it and I am sharing it with you and I think I will stop saying that I am not a Java person as Groovy and Grails stuff is pushing me into both Java and its ecosystem. The best example for explaining this would be security. Imagine you have a controller class that you don't want your regular members to access so you add `@RequireRole("Admin")` above your controller class. Whenever a member tries to access that annotated controller class they will be redirected to an unauthorized page unless they are admin. CREATING THE ANNOTATION ---------- For the beginning, lets create our annotation: //src/java/your/package/RequireRole.java package net.mengu.grails.sample; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD, ElementType.TYPE}) public @interface RequireRole { String value(); } What we should draw your attention here is that `ElementType.TYPE` makes the annotation available to classes and `ElementType.FIELD` makes the annotation available to controller actions. ANNOTATING THE CONTROLLER CLASS ---------- Now that we have created our annotation, we can annotate our controller class. package net.mengu.grails.sample @RequireRole("Admin") class SiteController { def index = { } } HOW TO CHECK THE CLASS ANNOTATION ---------- We are going good. Now the question pops up here. How do we check if user has the required role? In my opinion, Grails filters are a gift for this operation. We can create a filter in our `/grails-app/conf` directory named `SecurityFilters.groovy`. How do we find the controller class? Great question! We have grailsApplication exposed to us which also has controllerClasses property that we can use. We also know the name of the controller via `controllerName` property in our filter so let's act! //grails-app/conf/SecurityFilters.groovy import net.mengu.grails.sample.RequireRole class SecurityFilters { def filters = { loginCheck(controller:'*', action:'*') { before = { def controllerClass = grailsApplication.controllerClasses.find { it.fullName.indexOf(controllerName.capitalize()+"Controller") != -1 } def classAnnotated = controllerClass.getClazz().isAnnotationPresent(RequireRole) if (classAnnotated) { def requiredRole = controllerClass.getClazz().getAnnotation(RequireRole).value() if (session.user?.role != requiredRole) { redirect(uri:"/unauthorized") } } } } } } Let me explain what's going on over there in a minute. We are using before filter for every controller and every action. In our filter, we get the controller class as an object as we already have its name, we just get it from `grailsApplication.controllerClasses`. After that, we check if the class has the annotation and if it has the annotation present we get its value and we do our check. HOW TO CHECK THE ACTION ANNOTATION ---------- We are done with controlling the class annotation. How do we check the action annotation? It was a little bit tricky for me to do so as I am not a Grails Master yet. We have the controller class object already so what we need to do is getting the list of action objects. Action objects of a controller class can be accessed with `controllerClass.getClazz().declaredFields` so let's make an addition to `SecurityFilters.groovy` file. //grails-app/conf/SecurityFilters.groovy import net.mengu.grails.sample.RequireRole class SecurityFilters { def filters = { loginCheck(controller:'*', action:'*') { before = { def controllerClass = grailsApplication.controllerClasses.find { it.fullName.indexOf(controllerName.capitalize()+"Controller") != -1 } def classAnnotated = controllerClass.getClazz().isAnnotationPresent(RequireRole) if (classAnnotated) { def requiredRole = controllerClass.getClazz().getAnnotation(RequireRole).value() if (session.user?.role != requiredRole) { redirect(uri:"/unauthorized") } } if (actionName) { def controllerAction = controllerClass.getClazz().declaredFields.find { it.toString().indexOf(actionName) != -1 } def actionAnnotated = controllerAction.isAnnotationPresent(RequireRole) if (actionAnnotated) { def actionRequiredRole = controllerAction.getAnnotation(RequireRole).value() if (session.user?.role != actionRequiredRole) { redirect(uri:"/unauthorized") } } } } } } } That is all now. We have an annotation, we have annotated class and we have a mechanism processing what we need if the annotation is present. Hope you guys enjoyed the tutorial!
Did you enjoy this post? You should follow me on twitter here.

Comments

Alireza Haghighatkhah said on 26/02/2011 19:54 PM
Nice post, thanks for sharing.

Srinivas Chinthalapudi said on 16/06/2011 18:08 PM
Thanks a lot for a detailed explanation, as a newbie to Grails this is very useful.

Mengu Kagan said on 21/06/2011 02:44 AM
hi srinivas! you're welcome. :)

Leave a Response

No HTML allowed. You can use markdown.
Name*:
E-Mail* (not published):
Web site:
Response: