【问题标题】:In Grails 3.2.6, Async controller actions lose access to SecurityContextHolder在 Grails 3.2.6 中,异步控制器操作无法访问 SecurityContextHolder
【发布时间】:2017-07-03 10:30:10
【问题描述】:

这在 Grails 2 中不是问题,现在似乎只出现在 Grails 3 中。任何调用异步任务的控制器都无法在呈现视图时访问 SecurityContextHolder 以获取登录用户信息......

似乎在 SecurityContextPersistenceFilter 中,SecurityContextHolder.clearContext() 在 DispatcherServlet.processDispatchResult 能够呈现之前被调用,使得呈现代码无法访问存储在 SecurityContextHolder 中的登录用户信息:

    try {
        SecurityContextHolder.setContext(contextBeforeChainExecution);

        chain.doFilter(holder.getRequest(), holder.getResponse());

    }
    finally {
        SecurityContext contextAfterChainExecution = SecurityContextHolder
                .getContext();
        // Crucial removal of SecurityContextHolder contents - do this before anything
        // else.
        SecurityContextHolder.clearContext();
        repo.saveContext(contextAfterChainExecution, holder.getRequest(),
                holder.getResponse());
        request.removeAttribute(FILTER_APPLIED);

        if (debug) {
            logger.debug("SecurityContextHolder now cleared, as request processing completed");
        }
    }

起初我认为问题与安全上下文未传递到 Promise 的可运行文件(或类似的东西)有关,并且设置 springsecurity.sch.strategyName = "MODE_INHERITABLETHREADLOCAL" 无济于事。

以下是一些显示调试器的屏幕截图:

1) DispatcherServlet 中的这一行尚未执行。图片底部的 Watch 语句显示 .getAuthentication != null 返回 true

2) 在 SecurityContextPersistenceFilter 中清除 SecurityContextHolder 之前:

3) 从 ha.handle 返回后,.getAuthentication() 现在为 null

4) getAuthentication() 现在在渲染视图/结果之前为空

为了澄清,我试图从自定义标记库中访问 springSecurityService.currentUser,该标记库在布局中呈现我的页面标题。

所以,在 layout.gsp 类型的文件中:

<header id="header" class="md-whiteframe-1dp">
<g:renderHeader/></header>

使用 renderHeader 定义如下:

def renderHeader = { attrs, body ->

    SecUser currentUser = (SecUser) accountService.activeUser

    log.info("About to render header, session.id=" + session.id +
            (currentUser?.userLogLabel ?: " user=not_logged_in"))

    out << render(template: "/header", model: [currentUser : currentUser])
}

【问题讨论】:

  • 我开始觉得,当 sitemesh 正在执行并且涉及到异步时,sitemesh 失去了对 SecurityContextHolder 的句柄......

标签: grails asynchronous grails-3.0 grails3


【解决方案1】:

您是在控制器还是过滤器中执行此操作(我的意思是“过滤器”而不是“拦截器”)?

因为我可以毫无问题地从自定义 TokenFilter 中完美使用它。

这就是为什么我强烈主张将通信从业务逻辑转移到过滤器和处理程序拦截器,并停止将其与注释和其他东西联系起来。他们一遍又一遍地遇到这些问题。

我实际上刚刚发布了一个更快的 API 版本的 Grails,它昨天为大学处理了大部分这些通信问题

【讨论】:

  • 我注意到的问题是我的控制器正在渲染一个视图,并且视图使用的布局有一个正在访问 SCH 的自定义标记。正是在该标签内部(有助于为布局呈现内容),我看到登录用户无法访问。
【解决方案2】:

我遇到了同样的问题并设法找到了它。我假设您使用的是spring security core plugin。根本问题是 plugin registers an application filter 没有 DispatcherType.ASYNC。如果您查看 Spring 文档,spring security supports async。为了修复它,我创建了这个 BeanPostProcessor 并将它放在我的应用程序上下文中。

class SpringSecurityAsyncConfigurer implements BeanPostProcessor {
    @Override
    Object postProcessBeforeInitialization(final Object bean, final String beanName) throws BeansException {
        if (bean in FilterRegistrationBean && "springSecurityFilterChainRegistrationBean".equals(beanName)) {
            //for some unknown reason the plugin only has this run for request and error, adding async as the spring documentation
            //says this is supported
            bean.setDispatcherTypes(EnumSet.<DispatcherType>of(DispatcherType.REQUEST, DispatcherType.ERROR, DispatcherType.ASYNC))
        }
        bean
    }

    @Override
    Object postProcessAfterInitialization(final Object bean, final String beanName) throws BeansException {
        return bean
    }
}

【讨论】:

    猜你喜欢
    • 2013-06-10
    • 1970-01-01
    • 2017-10-08
    • 2013-12-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-24
    • 2015-02-06
    相关资源
    最近更新 更多