不可用安全管理器重写 shiro 会话道以记录即时登录用户信息时异常



我想用 redis 存储 shiro 会话,而不是默认方式。

然后我重写RedisSessionDao扩展EnterpriseCacheSessionDAO,如下所示:

@Repository
public class RedisSessionDao extends EnterpriseCacheSessionDAO {
private static final Logger logger = LoggerFactory.getLogger(RedisSessionDao.class);
@Autowired
private RedisTemplate<String, Object> redisTemplate;
public static final String KEY_PREFIX = "shiro_session_";
/**
* create session
* @param session
* @return
*/
@Override
protected Serializable doCreate(Session session) {
Serializable sessionId = super.doCreate(session);
// redis work
BoundValueOperations<String, Object> sessionValueOperations = redisTemplate.boundValueOps(KEY_PREFIX + sessionId.toString());
sessionValueOperations.set(session);
sessionValueOperations.expire(30, TimeUnit.MINUTES);
logger.info("create sessionId: " + sessionId);
return sessionId;
}
/**
* read session
* @param sessionId
* @return
*/
@Override
protected Session doReadSession(Serializable sessionId) {
Session session = super.doReadSession(sessionId);
logger.info("super.readSession: " + sessionId);
if (ServletUtil.getRequest() != null){  
logger.info("uri: " + ServletUtil.getRequest().getServletPath());
}
logger.info("session = " + (session == null ? null : "not null"));
if(session == null){
BoundValueOperations<String, Object> sessionValueOperations = redisTemplate.boundValueOps(KEY_PREFIX + sessionId.toString());
session = (Session) sessionValueOperations.get();
logger.info("session(redis) = " + (session == null ? null : "not null"));
}
return session;
}
/**
* update session
* @param session
*/
@Override
protected void doUpdate(Session session) {
super.doUpdate(session);
BoundValueOperations<String, Object> sessionValueOperations = redisTemplate.boundValueOps(KEY_PREFIX + session.getId().toString());
// If user is logined
/*SysAccount sysAccount = (SysAccount) SecurityUtils.getSubject().getPrincipal();
if (null != sysAccount) {
// record instant info like last_access_time, current ip
UserInfo info = new UserInfo(session.getId().toString(), sysAccount.getId(), session.getLastAccessTime(), session.getHost());
// put user info into redis. to do...
logger.info(JSON.toJSONString(info));
sessionValueOperations.set(session);
} else {
sessionValueOperations.set(session);
}*/
sessionValueOperations.set(session);
sessionValueOperations.expire(30, TimeUnit.MINUTES);
logger.info("update sessionId: " + session.getId().toString());
}
/**
* delete session
* @param session
*/
@Override
protected void doDelete(Session session) {
// sessionManager.getSessionDAO().delete(session)
redisTemplate.delete(KEY_PREFIX + session.getId().toString());
super.doDelete(session);
logger.info("delete sessionId: " + session.getId().toString());
}
}

但是当我尝试记录登录的用户即时信息(如last_access_time或当前 ip)时。

(请参阅doUpdate(Session session)方法中注释掉的代码)。

当我在已经登录后重新启动应用程序并刷新上一页(保持相同的会话ID)时,应用程序会抛出不可用SecurityManagerException,当我在已经登录并刷新页面之前重新启动应用程序时

可以。
org.apache.shiro.UnavailableSecurityManagerException: No SecurityManager accessible to the calling code, either bound to the org.apache.shiro.util.ThreadContext or as a vm static singleton.  This is an invalid application configuration.
at org.apache.shiro.SecurityUtils.getSecurityManager(SecurityUtils.java:123) ~[shiro-core-1.4.0.jar:1.4.0]
at org.apache.shiro.subject.Subject$Builder.<init>(Subject.java:626) ~[shiro-core-1.4.0.jar:1.4.0]
at org.apache.shiro.SecurityUtils.getSubject(SecurityUtils.java:56) ~[shiro-core-1.4.0.jar:1.4.0]
at com.enl.config.shiro.custom.RedisSessionDao.doUpdate(RedisSessionDao.java:85) ~[classes/:na]
at org.apache.shiro.session.mgt.eis.CachingSessionDAO.update(CachingSessionDAO.java:277) ~[shiro-core-1.4.0.jar:1.4.0]
at org.apache.shiro.session.mgt.eis.CachingSessionDAO$$FastClassBySpringCGLIB$$2a5e5afd.invoke(<generated>) ~[shiro-core-1.4.0.jar:1.4.0]
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) ~[spring-core-5.0.4.RELEASE.jar:5.0.4.RELEASE]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:747) ~[spring-aop-5.0.4.RELEASE.jar:5.0.4.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.0.4.RELEASE.jar:5.0.4.RELEASE]
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139) ~[spring-tx-5.0.4.RELEASE.jar:5.0.4.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) ~[spring-aop-5.0.4.RELEASE.jar:5.0.4.RELEASE]
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:689) ~[spring-aop-5.0.4.RELEASE.jar:5.0.4.RELEASE]
at com.enl.config.shiro.custom.RedisSessionDao$$EnhancerBySpringCGLIB$$400748cc.update(<generated>) ~[classes/:na]
at org.apache.shiro.session.mgt.DefaultSessionManager.onChange(DefaultSessionManager.java:212) ~[shiro-core-1.4.0.jar:1.4.0]
at org.apache.shiro.session.mgt.AbstractNativeSessionManager.setAttribute(AbstractNativeSessionManager.java:258) ~[shiro-core-1.4.0.jar:1.4.0]
at org.apache.shiro.session.mgt.DelegatingSession.setAttribute(DelegatingSession.java:151) ~[shiro-core-1.4.0.jar:1.4.0]
at org.apache.shiro.session.ProxiedSession.setAttribute(ProxiedSession.java:128) ~[shiro-core-1.4.0.jar:1.4.0]
at org.apache.shiro.mgt.DefaultSubjectDAO.mergePrincipals(DefaultSubjectDAO.java:222) ~[shiro-core-1.4.0.jar:1.4.0]
at org.apache.shiro.mgt.DefaultSubjectDAO.saveToSession(DefaultSubjectDAO.java:165) ~[shiro-core-1.4.0.jar:1.4.0]
at org.apache.shiro.mgt.DefaultSubjectDAO.save(DefaultSubjectDAO.java:146) ~[shiro-core-1.4.0.jar:1.4.0]
at org.apache.shiro.mgt.DefaultSecurityManager.save(DefaultSecurityManager.java:387) ~[shiro-core-1.4.0.jar:1.4.0]
at org.apache.shiro.mgt.DefaultSecurityManager.createSubject(DefaultSecurityManager.java:354) ~[shiro-core-1.4.0.jar:1.4.0]
at org.apache.shiro.subject.Subject$Builder.buildSubject(Subject.java:845) ~[shiro-core-1.4.0.jar:1.4.0]
at org.apache.shiro.web.subject.WebSubject$Builder.buildWebSubject(WebSubject.java:148) ~[shiro-web-1.4.0.jar:1.4.0]
at org.apache.shiro.web.servlet.AbstractShiroFilter.createSubject(AbstractShiroFilter.java:292) ~[shiro-web-1.4.0.jar:1.4.0]
at org.apache.shiro.web.servlet.AbstractShiroFilter.doFilterInternal(AbstractShiroFilter.java:359) ~[shiro-web-1.4.0.jar:1.4.0]
at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125) ~[shiro-web-1.4.0.jar:1.4.0]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.28.jar:8.5.28]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.28.jar:8.5.28]
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) ~[spring-web-5.0.4.RELEASE.jar:5.0.4.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.0.4.RELEASE.jar:5.0.4.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.28.jar:8.5.28]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.28.jar:8.5.28]
at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:109) ~[spring-web-5.0.4.RELEASE.jar:5.0.4.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.0.4.RELEASE.jar:5.0.4.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.28.jar:8.5.28]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.28.jar:8.5.28]
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:81) ~[spring-web-5.0.4.RELEASE.jar:5.0.4.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.0.4.RELEASE.jar:5.0.4.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.28.jar:8.5.28]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.28.jar:8.5.28]
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200) ~[spring-web-5.0.4.RELEASE.jar:5.0.4.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.0.4.RELEASE.jar:5.0.4.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.28.jar:8.5.28]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.28.jar:8.5.28]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199) ~[tomcat-embed-core-8.5.28.jar:8.5.28]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [tomcat-embed-core-8.5.28.jar:8.5.28]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:496) [tomcat-embed-core-8.5.28.jar:8.5.28]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140) [tomcat-embed-core-8.5.28.jar:8.5.28]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81) [tomcat-embed-core-8.5.28.jar:8.5.28]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87) [tomcat-embed-core-8.5.28.jar:8.5.28]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342) [tomcat-embed-core-8.5.28.jar:8.5.28]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:803) [tomcat-embed-core-8.5.28.jar:8.5.28]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) [tomcat-embed-core-8.5.28.jar:8.5.28]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:790) [tomcat-embed-core-8.5.28.jar:8.5.28]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1459) [tomcat-embed-core-8.5.28.jar:8.5.28]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-8.5.28.jar:8.5.28]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_131]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_131]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.5.28.jar:8.5.28]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_131]

我想这是因为SecurityUtils.getSubject().getPrincipal()不能在这里使用。

但我不知道了...

您可以避免调用当前主题购买将这些属性直接添加到会话中(而不是将信息带外获取)。 这也可以简化单元测试。

最新更新