Shiro:There is no session with id

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抛出来的:

login栈

实际上应用调用shior默认的subject.login(token)进行登录,是不应该去寻找sessionid的,而是通过seesionmanager生成一个新的sessionid.

创建方法0

可以看一下login的实现,通常是使用token参数就够了,框架获取当前的subject,再调用上图的login方法.

在看一下createSubject的过程,传入了三个参数,最后一个参数就是框架本身获取的.

创建方法1

创建方法内部,如果传入的subject不为空,则会进行设置上下文,一旦有了这个上下文,则会通过上下文去解析sessionkey,代码如下:

获取sessionkey

这里如果没有上下文,获取的key为空,如果获取到key,则进行session的解析处理,解析出现异常就出现了上面的堆栈信息,因为拿到的sessionId找不到实际的session内容.可能已过期可能已清理.

再回头看一下获取subject的过程:

获取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();

 

 

留下回复