这在 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])
}