tags:

views:

95

answers:

3

I have a service to get and set the user in the session. I would like to pass in some user information to each view if there is a logged in user and thought a filter would be the best way so I don't have to duplicate that in every controller/action. When I run the app, it get this error:

Error creating bean with name 'userService': Scope 'session' is not active for the current thread

My filter looks like this:

class SecurityFilters {
    def userService

    def filters = {
        setUser(controller:'*', action:'*') {
            before = {
                if (userService.isLoggedIn()) {
                    request.user = userService.getUser()
                } else {
                    request.user = null
                }
            }
        }
    }   
}

I know I can just ultimately access the user through session.user, but I want to be able to call userService.isLoggedIn() which I can't easily through the view. So is there a way to inject the service into the filter, or should I just create a taglib to wrap userService.isLoggedIn()?

+2  A: 

It looks like there are some problems with services in filters. This bug might point you in the right direction: http://jira.codehaus.org/browse/GRAILS-5982

You can also try to get a reference to your service through the ApplicationContext. Here's an example: http://stackoverflow.com/questions/2276624/how-do-i-get-an-instance-of-a-grails-service-programmatically

ataylor
+2  A: 

It looks like the problem is your userService is scoped to the session, and there is not necessarily a session at the time the attempt to inject the service into the filter happens.

If your userService is necessarily session-scoped then you need to use a scoped proxy in your spring config. E.g. in grails-app/conf/spring/resources.groovy:

import com.your.service.UserService
...
userServiceSession(UserService)
{ bean ->
    bean.scope = 'session'
}
userServiceSessionProxy(org.springframework.aop.scope.ScopedProxyFactoryBean)
{
    targetBeanName = 'userServiceSession'
    proxyTargetClass = true
}

Then rename your injected variable in your SecurityFilter:

def userServiceSessionProxy

(and obviously rename where you use it elsewhere in the class).

What this should do is inject the proxy at injection time, but only go to the actual service at the time the filter is executed (when there is a session).

Note: not sure whether doing this still lets other places where there will be a session (e.g. controllers) still reference the service as 'userService', if not you might be able to rename userServiceSession to userService in resources.groovy (and update targetBeanName accordingly).

Chris
This sounds like it a valid solution, but I opted switching over to a taglib instead. Seemed simpler.
varikin
A: 

As Chris pointed out, my service was session scoped. It seemed more a hassle to get it working as a filter so I switched over to use a taglib to load the head into the page with the correct login/logout link.

So to me the correct answer is to use a taglib instead of filters when a service is needed.

varikin
So for you the answer to the question : 'Can I inject a service into a filter in Grails?' is 'use a taglib' ? It doesn't sound like a genuine answer to me...
fabien7474
It is in this scenario. So no, I couldn't inject the service into the filter. But I can use a taglib instead of a filter.
varikin