这在Grails 2中不是问题,现在只出现在Grails 3中。任何调用异步任务的控制器都无法访问SecurityContextHolder以在呈现视图时获取登录的用户信息。 ..
似乎在SecurityContextPersistenceFilter中,在DispatcherServlet.processDispatchResult能够呈现之前调用SecurityContextHolder.clearContext(),使得呈现代码无法访问存储在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的runnable(或某些这样的东西)有关,并设置springsecurity.sch.strategyName =" MODE_INHERITABLETHREADLOCAL"无济于事。
以下是显示调试器的一些屏幕截图:
1)DispatcherServlet中的这一行尚未执行。图像底部的监视语句显示.getAuthentication!= null返回true
2)在SecurityContextPersistenceFilter中清除SecurityContextHolder之前:
3)从ha.handle返回后,.getAuthentication()现在为null
4)在渲染视图/结果之前,getAuthentication()现在为null
为了澄清,我试图从一个自定义标记库中访问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])
}
答案 0 :(得分:1)
我遇到了同样的问题并设法追踪它。我假设您正在使用spring security core plugin。根本问题是没有DispatcherType.ASYNC的plugin registers an application filter。如果您查看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
}
}
答案 1 :(得分:0)
你是在控制器还是过滤器中做这个(我的意思是'过滤器'不是'拦截器')?
因为我可以在没有问题的情况下从自定义TokenFilter中完美地使用它。
这就是为什么我强烈要求将通信从业务逻辑转移到更高级别的过滤器和处理程序拦截器,并停止将其与注释和内容联系起来。他们一遍又一遍地遇到这些问题。
我实际上刚刚发布了一个更快版本的Grails for API,它负责昨天大学的大部分通信问题