8.5 Filters 2.4.4

See the light - agile, industrial strength, rapid web application development made easy

(Quick Reference) # 8.5 Filters - Reference Documentation Authors: Graeme Rocher, Peter Ledbrook, Marc Palmer, Jeff Brown, Luke Daley, Burt Beckwith, Lari Hotari Version: 2.4.4 ## Table of Contents ## 8.5 Filters Although Grails controllers support fine grained interceptors, these are only really useful when applied to a few controllers and become difficult to manage with larger applications. Filters on the other hand can be applied across a whole group of controllers, a URI space or to a specific action. Filters are far easier to plugin and maintain completely separately to your main controller logic and are useful for all sorts of cross cutting concerns such as security, logging, and so on. ## 8.5.1 Applying Filters 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:
    class ExampleFilters {
       def filters = {
            // your filters here
       }
    }
Each filter you define within the `filters` block has a name and a scope. The name is the method name and the scope is defined using named arguments. For example to define a filter that applies to all controllers and all actions you can use wildcards:
    sampleFilter(controller:'*', action:'*') {
      // interceptor definitions
    }
The scope of the filter can be one of the following things: A controller and/or action name pairing with optional wildcards A URI, with Ant path matching syntax Filter rule attributes: `controller` - controller matching pattern, by default * is replaced with .* and a regex is compiled `controllerExclude` - controller exclusion pattern, by default * is replaced with .* and a regex is compiled `action` - action matching pattern, by default * is replaced with .* and a regex is compiled `actionExclude` - action exclusion pattern, by default * is replaced with .* and a regex is compiled `regex` (`true`/`false`) - use regex syntax (don't replace '*' with '.*') `uri` - a uri to match, expressed with as Ant style path (e.g. /book/**) `uriExclude` - a uri pattern to exclude, expressed with as Ant style path (e.g. /book/**) `find` (`true`/`false`) - rule matches with partial match (see `java.util.regex.Matcher.find()`) `invert` (`true`/`false`) - invert the rule (NOT rule) Some examples of filters include: All controllers and actions

    all(controller: '*', action: '*') {}
Only for the `BookController`

    justBook(controller: 'book', action: '*') {}
All controllers except the `BookController`

    notBook(controller: 'book', invert: true) {}
All actions containing 'save' in the action name

    saveInActionName(action: '*save*', find: true) {}
All actions starting with the letter 'b' except for actions beginning with the phrase 'bad*'

    actionBeginningWithBButNotBad(action: 'b*', actionExclude: 'bad*', find: true) {}
Applied to a URI space

    someURIs(uri: '/book/**') {}
Applied to all URIs

    allURIs(uri: '/**') {}
In addition, the order in which you define the filters within the `filters` code block dictates the order in which they are executed. To control the order of execution between `Filters` classes, you can use the `dependsOn` property discussed in filter dependencies section. Note: When exclude patterns are used they take precedence over the matching patterns. For example, if action is 'b*' and actionExclude is 'bad*' then actions like 'best' and 'bien' will have that filter applied but actions like 'bad' and 'badlands' will not. ## 8.5.2 Filter Types Within the body of the filter you can then define one or several of the following interceptor types for the filter: `before` - Executed before the action. Return `false` to indicate that the response has been handled that that all future filters and the action should not execute `after` - Executed after an action. Takes a first argument as the view model to allow modification of the model before rendering the view `afterView` - Executed after view rendering. Takes an Exception as an argument which will be non-`null` if an exception occurs during processing. Note: this Closure is called before the layout is applied. For example to fulfill the common simplistic authentication use case you could define a filter as follows:
    class SecurityFilters {
       def filters = {
           loginCheck(controller: '*', action: '*') {
               before = {
                  if (!session.user && !actionName.equals('login')) {
                      redirect(action: 'login')
                      return false
                   }
               }
           }
       }
    }
Here the `loginCheck` filter uses a `before` interceptor to execute a block of code that checks if a user is in the session and if not redirects to the login action. Note how returning false ensure that the action itself is not executed. Here's a more involved example that demonstrates all three filter types:

    import java.util.concurrent.atomic.AtomicLongclass LoggingFilters {   private static final AtomicLong REQUEST_NUMBER_COUNTER = new AtomicLong()
       private static final String START_TIME_ATTRIBUTE = 'Controller__START_TIME__'
       private static final String REQUEST_NUMBER_ATTRIBUTE = 'Controller__REQUEST_NUMBER__'   def filters = {      logFilter(controller: '*', action: '*') {         before = {
                if (!log.debugEnabled) return true            long start = System.currentTimeMillis()
                long currentRequestNumber = REQUEST_NUMBER_COUNTER.incrementAndGet()            request[START_TIME_ATTRIBUTE] = start
                request[REQUEST_NUMBER_ATTRIBUTE] = currentRequestNumber            log.debug "preHandle request #$currentRequestNumber : " +
                   "'$request.servletPath'/'$request.forwardURI', " +
                   "from $request.remoteHost ($request.remoteAddr) " +
                   " at ${new Date()}, Ajax: $request.xhr, controller: $controllerName, " +
                   "action: $actionName, params: ${new TreeMap(params)}"            return true
             }         after = { Map model ->            if (!log.debugEnabled) return true            long start = request[START_TIME_ATTRIBUTE]
                long end = System.currentTimeMillis()
                long requestNumber = request[REQUEST_NUMBER_ATTRIBUTE]            def msg = "postHandle request #$requestNumber: end ${new Date()}, " +
                          "controller total time ${end - start}ms"
                if (log.traceEnabled) {
                	log.trace msg + "; model: $model"
                }
                else {
                	log.debug msg
                }
             }         afterView = { Exception e ->            if (!log.debugEnabled) return true            long start = request[START_TIME_ATTRIBUTE]
                long end = System.currentTimeMillis()
                long requestNumber = request[REQUEST_NUMBER_ATTRIBUTE]            def msg = "afterCompletion request #$requestNumber: " +
                          "end ${new Date()}, total time ${end - start}ms"
                if (e) {
                   log.debug "$msg \n\texception: $e.message", e
                }
                else {
                   log.debug msg
                }
             }
          }
       }
    }
In this logging example we just log various request information, but note that the `model` map in the `after` filter is mutable. If you need to add or remove items from the model map you can do that in the `after` filter. ## 8.5.3 Variables and Scopes Filters support all the common properties available to controllers and tag libraries, plus the application context: request - The HttpServletRequest object response - The HttpServletResponse object session - The HttpSession object servletContext - The ServletContext object flash - The flash object params - The request parameters object actionName - The action name that is being dispatched to controllerName - The controller name that is being dispatched to grailsApplication - The Grails application currently running applicationContext - The ApplicationContext object However, filters only support a subset of the methods available to controllers and tag libraries. These include: redirect - For redirects to other controllers and actions render - For rendering custom responses ## 8.5.4 Filter Dependencies In a `Filters` class, you can specify any other `Filters` classes that should first be executed using the `dependsOn` property. This is used when a `Filters` class depends on the behavior of another `Filters` class (e.g. setting up the environment, modifying the request/session, etc.) and is defined as an array of `Filters` classes. Take the following example `Filters` classes:

    class MyFilters {
        def dependsOn = [MyOtherFilters]    def filters = {
            checkAwesome(uri: "/*") {
                before = {
                    if (request.isAwesome) { // do something awesome }
                }
            }        checkAwesome2(uri: "/*") {
                before = {
                    if (request.isAwesome) { // do something else awesome }
                }
            }
        }
    }
    class MyOtherFilters {
        def filters = {
            makeAwesome(uri: "/*") {
                before = {
                    request.isAwesome = true
                }
            }
            doNothing(uri: "/*") {
                before = {
                    // do nothing
                }
            }
        }
    }
MyFilters specifically `dependsOn` MyOtherFilters. This will cause all the filters in MyOtherFilters whose scope matches the current request to be executed before those in MyFilters. For a request of "/test", which will match the scope of every filter in the example, the execution order would be as follows: MyOtherFilters - makeAwesome MyOtherFilters - doNothing MyFilters - checkAwesome MyFilters - checkAwesome2 The filters within the MyOtherFilters class are processed in order first, followed by the filters in the MyFilters class. Execution order between `Filters` classes are enabled and the execution order of filters within each `Filters` class are preserved. If any cyclical dependencies are detected, the filters with cyclical dependencies will be added to the end of the filter chain and processing will continue. Information about any cyclical dependencies that are detected will be written to the logs. Ensure that your root logging level is set to at least WARN or configure an appender for the Grails Filters Plugin (`org.codehaus.groovy.grails.plugins.web.filters.FiltersGrailsPlugin`) when debugging filter dependency issues. | Quick Reference (hide)