Shiro:There is no session with id
最近通过shiro开发一个基于dubbo的鉴权服务,在测试阶段登录的场景下遇到这个问题,做个记录。
异常信息如下:
org.apache.shiro.session.UnknownSessionException: There is no session with id [53e6888f-3e33-4aee-b369-54e849c49ff3] at org.apache.shiro.session.mgt.eis.AbstractSessionDAO.readSession(AbstractSessionDAO.java:170) at org.apache.shiro.session.mgt.eis.CachingSessionDAO.readSession(CachingSessionDAO.java:261) at org.apache.shiro.session.mgt.DefaultSessionManager. retrieveSessionFromDataSource(DefaultSessionManager.java:236) at org.apache.shiro.session.mgt.DefaultSessionManager. retrieveSession(DefaultSessionManager.java:222) at org.apache.shiro.session.mgt.AbstractValidatingSessionManager. doGetSession(AbstractValidatingSessionManager.java:118) at org.apache.shiro.session.mgt.AbstractNativeSessionManager. lookupSession(AbstractNativeSessionManager.java:105) at org.apache.shiro.session.mgt.AbstractNativeSessionManager. getSession(AbstractNativeSessionManager.java:97) at org.apache.shiro.mgt.SessionsSecurityManager.getSession(SessionsSecurityManager.java:125)
异常是由DefaultSessionManager抛出来的:
实际上应用调用shior默认的subject.login(token)进行登录,是不应该去寻找sessionid的,而是通过seesionmanager生成一个新的sessionid.
可以看一下login的实现,通常是使用token参数就够了,框架获取当前的subject,再调用上图的login方法.
在看一下createSubject的过程,传入了三个参数,最后一个参数就是框架本身获取的.
创建方法内部,如果传入的subject不为空,则会进行设置上下文,一旦有了这个上下文,则会通过上下文去解析sessionkey,代码如下:
这里如果没有上下文,获取的key为空,如果获取到key,则进行session的解析处理,解析出现异常就出现了上面的堆栈信息,因为拿到的sessionId找不到实际的session内容.可能已过期可能已清理.
再回头看一下获取subject的过程:
框架本身维持了一个ThreadLocal,用来和当前线程绑定subject,在多线程的环境下,使用同一个subject实例则会导致其他线程登录后获取到共同的上下文,导致异常,例如:
//异常代码: Subject subject = SecurityUtils.getSubject(); //正常代码: Subject subject = SecurityUtils.getSecurityManager().createSubject(new DefaultSubjectContext());
通过sessionid获取subject:
Session session = SecurityUtils.getSecurityManager().getSession(new DefaultSessionKey(sessionId)); Subject subject = new Subject.Builder().session(session) .sessionId(new DefaultSessionKey(session.getId())).buildSubject();