目录
Junit+Spring MockMvc+Shiro时出现SessionContext和SecurityManager的错误解决方式
使用Junit测试SpringMvc,用spring-test MockMvc的时候,由于系统里配置了shiro。
导致一些奇怪的错误。
第一个错误
org.apache.shiro.UnavailableSecurityManagerException: No SecurityManager accessible to the calling code, either bound to the org.apache.shiro.util.ThreadContextor as a vm static singleton. This is an invalid application configuration.
这个错误我用了这个方法来解决:
@Before
public void setShiro() {
SecurityUtils.setSecurityManager(context.getBean(SecurityManager.class));
}
这个解决方法互联网上很多人都说了。
然后又出现了第二个错误。
第二个错误
java.lang.IllegalArgumentException: SessionContext must be an HTTP compatible implementation.
at org.apache.shiro.web.session.mgt.ServletContainerSessionManager.createSession(ServletContainerSessionManager.java:103)
at org.apache.shiro.web.session.mgt.ServletContainerSessionManager.start(ServletContainerSessionManager.java:64)
at org.apache.shiro.mgt.SessionsSecurityManager.start(SessionsSecurityManager.java:121)
at org.apache.shiro.subject.support.DelegatingSubject.getSession(DelegatingSubject.java:336)
at org.apache.shiro.subject.support.DelegatingSubject.getSession(DelegatingSubject.java:314)
然后这个错误是遍查网上都没有啊。于是我开始调试源码(这是我经常的手段)
PS:my version : shiro-1.2.0
首先定位到错误堆栈信息最上层,因为Exception就是从这里抛出的。
有很多经验不足的开发者,碰到异常总不知所措。最好的方法就是追根溯源,看它哪里报错。
protected Session createSession(SessionContext sessionContext) throws AuthorizationException {
if (!WebUtils.isHttp(sessionContext)) {
String msg = "SessionContext must be an HTTP compatible implementation.";
throw new IllegalArgumentException(msg);
} else {
HttpServletRequest request = WebUtils.getHttpRequest(sessionContext);
HttpSession httpSession = request.getSession();
String host = this.getHost(sessionContext);
return this.createSession(httpSession, host);
}
}
看到是一个判断条件为false了。我现在是debug模式,F5跟进去,发现里面还有一个重载。
private static boolean isHttp(RequestPairSource source) {
ServletRequest request = source.getServletRequest();
ServletResponse response = source.getServletResponse();
return request instanceof HttpServletRequest && response instanceof HttpServletResponse;
}
最后我发现request和response是null。null instanceof anything always return false。
知道原因之后,我就开始往上层代码找
最后找到是Shiro里面的SubjectContext
里面的setServletRequest
和setServletResponse
方法根本没有调用,导致为null。
由于我的项目正常启动不报错,就是junit报错,于是我在这两个方法中下了断点(这几个类maven好像没有源码,只是class,idea反编译的,不能查找。)
然后我正常启动项目,在堆栈里发现是AbstractShiroFIlter调用的,有了这个线索,解决方式就水落石出了。原来是ShiroFIlter在junit,mockmvc环境中没有被加入。
解决方法
最后解决方式是:
DefaultMockMvcBuilder<DefaultMockMvcBuilder<?>> builder = MockMvcBuilders.webAppContextSetup(context);
//这一句
builder.addFilters((Filter) context.getBean("shiroFilter"));
然后我尝试把第一个错误的解决代码去掉,发现也能正常运行。
……。
就到这里吧,我本来就不是喜欢写博客的人,突然想记录一下自己的解决问题的过程,分享给大家,希望大家喜欢。
过去工作中,好多类似的奇葩问题,我都没有记录博客,现在想起来也有点遗憾。不过都记在我心里了,如果以后再碰到,我条件反射就会解决了,那时候再记下来吧。