问题排查
这个问题实际是 Oauth2在创建OauthContext时绑定了Session而在获取Session时是从RequestContextHolder中获取的,代码在SessionScope类中如下:
@Override
public Object get(String name, ObjectFactory<?> objectFactory) {
Object mutex = RequestContextHolder.currentRequestAttributes().getSessionMutex();
synchronized (mutex) {
return super.get(name, objectFactory);
}
}
而此时RequestContextHolder.currentRequestAttributes()返回的值为空并抛出了IllegalStateException异常
导致问题的原因
RequestContextHolder这个是Spring中的一个持有类在Request请求进来时进行初始化并将Request的信息保存起来,在需要的地方可以不传入Request 而直接使用0currentRequestAttributes()或者getRequestAttributes获取Request中的信息,这个信息是在RequestContextFilter中被初始化的,代码如下:
@Override
protected void doFilterInternal(
//忽略不重要的代码
//这里进行将Request中的信息保存到RequestContextHolder中
initContextHolders(request, attributes);
try {
filterChain.doFilter(request, response);
}
finally {
resetContextHolders();
if (logger.isTraceEnabled()) {
logger.trace("Cleared thread-bound request context: " + request);
}
attributes.requestCompleted();
}
}
/**
* 将Request中的信息保存到RequestContextHolder中
*/
private void initContextHolders(HttpServletRequest request, ServletRequestAttributes requestAttributes) {
LocaleContextHolder.setLocale(request.getLocale(), this.threadContextInheritable);
RequestContextHolder.setRequestAttributes(requestAttributes, this.threadContextInheritable);
if (logger.isTraceEnabled()) {
logger.trace("Bound request context to thread: " + request);
}
}
如果信息没有被初始化,原因有这么几个
- 一、RequestContextFilter没有被加入到系统中(这个可以从ApplicationFilterChain.filters中查看到)
- 二、RequestContextFilter虽然被加入到系统中了但是被排在了springSecurityFilter后面
注意:Spring mvc 默认使用的是OrderedRequestContextFilter 在配置类WebMvcAutoConfiguration中完成的配置,但是只有WebMvcConfigurationSupport 没有在Spring容器中时才会生效,所以这个问题大概率是由于自定义了WebMvcConfigurationSupport 导致的
问题解决
问题找到了可以通过以下解决方案解决
- 更换使用WebMvcConfigurer接口进行对SpringMvc的配置
- 如果必须使用自定义的WebMvcConfigurationSupport 那就需要自己手动加入RequestContextFilter并且保证其排在springSecurityFilter之前。