开发者

Can I inject a service into a filter in Grails?

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()?


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).


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

You can also try to get a reference to your service through the ApplicationContext. Here's an example: How do I get an instance of a Grails service programmatically?


import org.codehaus.groovy.grails.web.context.ServletContextHolder
import org.springframework.context.ApplicationContext
import org.springframework.web.context.support.WebApplicationContextUtils
class SecurityFilters {
    def userService

    def filters = {
        setUser(controller:'*', action:'*') {
            before = {
                def servletCtx = ServletContextHolder.getServletContext()
                ApplicationContext applicationContext = WebApplicationContextUtils.
                    getRequiredWebApplicationContext(servletCtx)
                userService =applicationContext.getBean('userService')
                if (userService.isLoggedIn()) {
                    request.user = userService.getUser()
                } else {
                    request.user = null
                }
            }
        }
    }   
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜