NutzCN Logo
问答 每个账户同时只能有一个人登录或几个人同时登录,如果同时有多人登录:要么不让后者登录;要么踢出前者登录(强制退出),nutzbook如何实现?
发布于 2779天前 作者 binfoo 8050 次浏览 复制 上一个帖子 下一个帖子
标签:

每个账户同时只能有一个人登录或几个人同时登录,如果同时有多人登录:要么不让后者登录;要么踢出前者登录(强制退出),nutzbook如何实现?

56 回复

redis记录登陆的用户的id及sessionid,后者登陆时,去redis中取出前者踢出即可

你纠结的是如何记录前一个session id?

是的,怎么记录

基本思路如下:

// 不允许后者登录
Long re = jedis().setnx("u:sid:"+uid, sessionid);
if (re == 0) {
    // 老session id存在, 检查一下是否过期. 如果没过期, 拒绝登录
}
shiro.login(...);

String oldSessionId = jedis().getSet("u:sid:"+uid, sessionid);
if (oldSessionId != null) {
    // 老session id存在, 取出session, 注销掉
}
shiro.login(...);

这个好像只允许一个登录,如果同一账号允许3个的话如何处理?

在redis中记录一个sessionId的sortedset集合,每次登陆时,比较一下集合的大小,大于3个时,把最老的sessionId登出

jedis().zadd("u:sid:" + uid, System.currentTimeMillis(), sessionId);

如果我销毁老的sessionId,怎么从sessionId获取到HttpSession对象

@binfoo 是shiro还是http session哦

HttpSession session

    @At
    public Object login(@Param("username") String username, @Param("password") String password,
                        @Param("captcha") String captcha,
                        @Attr(scope = Scope.SESSION, value = "nutz_captcha") String _captcha,
                        HttpSession session) {
        NutMap re = new NutMap();
        if (!Toolkit.checkCaptcha(_captcha, captcha)) {
            return re.setv("ok", false).setv("msg", "验证码错误");
        }

        int userId = userService.fetch(username, password);
        if (userId < 0) {
            return re.setv("ok", false).setv("msg", "用户名或密码错误");
        } else {
//            Long usid = jedis().setnx("u:sid:"+userId, session.getId());

            String key = "u:sid:" + userId;

            jedisAgent.getResource().zadd(key, System.currentTimeMillis(), session.getId());//加入

            Long size = jedisAgent.getResource().zcard(key);//求个数

            log.info("session.size: " + size);

            if (size > MAX_USER_ONLINE) {

                jedisAgent.getResource().zrange(key, 0, 100);//zrange(key, start, end):返回名称为key的zset(元素已按score从小到大排序)中的index从start到end的所有元素

                String deleteMember = jedisAgent.getResource().mget(key).get(0);

                log.info("sessionid :" + deleteMember);

                //销毁老的

                session.getSessionContext().getSession(deleteMember).invalidate();

                jedisAgent.getResource().zremrangeByRank(key, 0, 1);//删掉第一个

            }

            session.setAttribute("me", userId);
            // 完成nutdao_realm后启用.
            SecurityUtils.getSubject().login(new SimpleShiroToken(userId));

            return re.setv("ok", true);
        }
    }

@binfoo 那就是shiro session咯,SecurityUtils类有方法

@SessionBy(ShiroSessionProvider.class)
这个是MainModule里面的,应该是自定义的shiro session

public Object login(@Param("username") String username, @Param("password") String password,
@Param("captcha") String captcha,
@Attr(scope = Scope.SESSION, value = "nutz_captcha") String _captcha,
HttpSession session)
这个入参数是HttpSession,我想要shrio的缓存session,并且能够进行增删操作

SecurityUtils.getSecurityManager().getSession("Key");是这个方法吗,这个key如何实现的

key就是session id嘛

shrio生成的session和直接HttpSession session入参是一个吗?

都是Shiro Session, 容器自身的session已经被shiro屏蔽了

实现新登陆的踢出老用户,取出来老的session然后注销,我的代码应该是不对的,求指教,对shiro不熟悉

            Redis GETSET命令在Redis键中设置指定的字符串值,并返回其旧值。
//
//            返回值
//
//            返回一个字符串,也就是键的旧值。 如果键不存在,则返回nil。


            final String oldSessinId = jedisPool.getResource().getSet("u:sid:" + userId, session.getId());
            
            //取出来老的sessionId,然后注销掉,新登陆的踢掉老的用户

            if (oldSessinId != null) {
                Session  sessionOld = SecurityUtils.getSecurityManager().getSession(new SessionKey() {
                    @Override
                    public Serializable getSessionId() {
                        return oldSessinId;
                    }
                });
                SecurityUtils.getSecurityManager().logout(subject);
            }

            // 完成nutdao_realm后启用.
            subject.login(new SimpleShiroToken(userId));

//            subject.getSession().setAttribute("me", userId);

            return re.setv("ok", true);
        }

不会取出来,不会注销

new Subject.Builder().sessionId(oldSessionId).buildSubject().logout();

日志报错

3c3e919c6cec
2017-04-10 17:18:07,561 org.apache.shiro.mgt.DefaultSecurityManager.resolveSession(DefaultSecurityManager.java:447) DEBUG - Resolved SubjectContext context session is invalid.  Ignoring and creating an anonymous (session-less) Subject instance.
org.apache.shiro.session.UnknownSessionException: There is no session with id [9216e0fe-75a0-47ec-a04c-3c3e919c6cec]
	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:148)
	at org.apache.shiro.session.mgt.AbstractNativeSessionManager.getSession(AbstractNativeSessionManager.java:140)
	at org.apache.shiro.mgt.SessionsSecurityManager.getSession(SessionsSecurityManager.java:156)
	at org.apache.shiro.mgt.DefaultSecurityManager.resolveContextSession(DefaultSecurityManager.java:456)
	at org.apache.shiro.mgt.DefaultSecurityManager.resolveSession(DefaultSecurityManager.java:442)
	at org.apache.shiro.mgt.DefaultSecurityManager.createSubject(DefaultSecurityManager.java:338)
	at org.apache.shiro.subject.Subject$Builder.buildSubject(Subject.java:846)
	at com.binfoo.www.module.UserModule.login(UserModule.java:97)
	at com.binfoo.www.module.UserModule$$NUTZAOP._aop_invoke(UserModule.java:2)
	at org.nutz.aop.InterceptorChain.invoke(InterceptorChain.java:77)
	at org.nutz.aop.InterceptorChain.doChain(InterceptorChain.java:57)
	at org.nutz.integration.jedis.RedisInterceptor.filter(RedisInterceptor.java:24)
	at org.nutz.aop.InterceptorChain.doChain(InterceptorChain.java:60)
	at com.binfoo.www.module.UserModule$$NUTZAOP.login(UserModule.java:1)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:497)
	at org.nutz.mvc.impl.processor.MethodInvokeProcessor.process(MethodInvokeProcessor.java:25)
	at org.nutz.mvc.impl.processor.AbstractProcessor.doNext(AbstractProcessor.java:44)
	at org.nutz.mvc.impl.processor.AdaptorProcessor.process(AdaptorProcessor.java:33)
	at org.nutz.mvc.impl.processor.AbstractProcessor.doNext(AbstractProcessor.java:44)
	at org.nutz.mvc.impl.processor.ActionFiltersProcessor.process(ActionFiltersProcessor.java:58)
	at org.nutz.mvc.impl.processor.AbstractProcessor.doNext(AbstractProcessor.java:44)
	at org.nutz.integration.shiro.NutShiroProcessor.process(NutShiroProcessor.java:126)
	at org.nutz.mvc.impl.processor.AbstractProcessor.doNext(AbstractProcessor.java:44)
	at org.nutz.mvc.impl.processor.ModuleProcessor.process(ModuleProcessor.java:123)
	at org.nutz.mvc.impl.processor.AbstractProcessor.doNext(AbstractProcessor.java:44)
	at org.nutz.mvc.impl.processor.EncodingProcessor.process(EncodingProcessor.java:27)
	at org.nutz.mvc.impl.processor.AbstractProcessor.doNext(AbstractProcessor.java:44)
	at org.nutz.mvc.impl.processor.UpdateRequestAttributesProcessor.process(UpdateRequestAttributesProcessor.java:15)
	at org.nutz.mvc.impl.processor.AbstractProcessor.doNext(AbstractProcessor.java:44)
	at com.binfoo.www.mvc.LogTimeProcessor.process(LogTimeProcessor.java:22)
	at org.nutz.mvc.impl.NutActionChain.doChain(NutActionChain.java:44)
	at org.nutz.mvc.impl.ActionInvoker.invoke(ActionInvoker.java:67)
	at org.nutz.mvc.ActionHandler.handle(ActionHandler.java:31)
	at org.nutz.mvc.NutFilter.doFilter(NutFilter.java:198)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
	at com.alibaba.druid.support.http.WebStatFilter.doFilter(WebStatFilter.java:123)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
	at org.apache.shiro.web.servlet.ProxiedFilterChain.doFilter(ProxiedFilterChain.java:61)
	at org.apache.shiro.web.servlet.AdviceFilter.executeChain(AdviceFilter.java:108)
	at org.apache.shiro.web.servlet.AdviceFilter.doFilterInternal(AdviceFilter.java:137)
	at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125)
	at org.apache.shiro.web.servlet.ProxiedFilterChain.doFilter(ProxiedFilterChain.java:66)
	at org.apache.shiro.web.servlet.AbstractShiroFilter.executeChain(AbstractShiroFilter.java:449)
	at org.apache.shiro.web.servlet.AbstractShiroFilter$1.call(AbstractShiroFilter.java:365)
	at org.apache.shiro.subject.support.SubjectCallable.doCall(SubjectCallable.java:90)
	at org.apache.shiro.subject.support.SubjectCallable.call(SubjectCallable.java:83)
	at org.apache.shiro.subject.support.DelegatingSubject.execute(DelegatingSubject.java:383)
	at org.apache.shiro.web.servlet.AbstractShiroFilter.doFilterInternal(AbstractShiroFilter.java:362)
	at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:212)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:141)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
	at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:522)
	at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1095)
	at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:672)
	at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.doRun(AprEndpoint.java:2500)
	at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.run(AprEndpoint.java:2489)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
	at java.lang.Thread.run(Thread.java:745)
2017-04-10 17:18:07,564 org.apache.shiro.web.mgt.CookieRememberMeManager.getRememberedSerializedIdentity(CookieRememberMeManager.java:192) DEBUG - SubjectContext argument is not an HTTP-aware instance.  This is required to obtain a servlet request and response in order to retrieve the rememberMe cookie. Returning immediately and ignoring rememberMe operation.
2017-04-10 17:18:07,564 org.nutz.ioc.impl.NutIoc.get(NutIoc.java:151) DEBUG - Get 'dao'<interface org.nutz.dao.Dao>
2017-04-10 17:18:07,565 org.nutz.plugins.cache.dao.CachedNutDaoExecutor.exec(CachedNutDaoExecutor.java:147) DEBUG - sql = SELECT * FROM t_user  WHERE id=?, tables = [t_user]
2017-04-10 17:18:07,565 org.nutz.plugins.cache.dao.CachedNutDaoExecutor.exec(CachedNutDaoExecutor.java:177) DEBUG - not good for cache >> SELECT * FROM t_user  WHERE id=?
2017-04-10 17:18:07,565 org.nutz.dao.impl.sql.run.NutDaoExecutor.printSQL(NutDaoExecutor.java:388) DEBUG - SELECT * FROM t_user  WHERE id=?
    | 1 |
    |---|
    | 1 |
  For example:> "SELECT * FROM t_user  WHERE id=1"
2017-04-10 17:18:07,571 org.apache.shiro.realm.AuthenticatingRealm.getAuthenticationInfo(AuthenticatingRealm.java:569) DEBUG - Looked up AuthenticationInfo [1] from doGetAuthenticationInfo
2017-04-10 17:18:07,572 org.apache.shiro.realm.AuthenticatingRealm.cacheAuthenticationInfoIfPossible(AuthenticatingRealm.java:507) DEBUG - AuthenticationInfo caching is disabled for info [1].  Submitted token: [org.nutz.integration.shiro.SimpleShiroToken@5bbd0f27].
2017-04-10 17:18:07,572 org.apache.shiro.authc.AbstractAuthenticator.authenticate(AbstractAuthenticator.java:233) DEBUG - Authentication successful for token [org.nutz.integration.shiro.SimpleShiroToken@5bbd0f27].  Returned account [1]
2017-04-10 17:18:07,572 org.apache.shiro.subject.support.DefaultSubjectContext.resolveSecurityManager(DefaultSubjectContext.java:102) DEBUG - No SecurityManager available in subject context map.  Falling back to SecurityUtils.getSecurityManager() lookup.
2017-04-10 17:18:07,572 org.apache.shiro.mgt.DefaultSecurityManager.resolveSession(DefaultSecurityManager.java:436) DEBUG - Context already contains a session.  Returning.
2017-04-10 17:18:07,572 org.apache.shiro.subject.support.DefaultSubjectContext.resolveSecurityManager(DefaultSubjectContext.java:102) DEBUG - No SecurityManager available in subject context map.  Falling back to SecurityUtils.getSecurityManager() lookup.
2017-04-10 17:18:07,572 org.apache.shiro.web.servlet.SimpleCookie.addCookieHeader(SimpleCookie.java:226) DEBUG - Added HttpServletResponse Cookie [rememberMe=deleteMe; Path=/; Max-Age=0; Expires=Sun, 09-Apr-2017 09:18:07 GMT]
2017-04-10 17:18:07,573 org.apache.shiro.mgt.AbstractRememberMeManager.onSuccessfulLogin(AbstractRememberMeManager.java:290) DEBUG - AuthenticationToken did not indicate RememberMe is requested.  RememberMe functionality will not be executed for corresponding account.
2017-04-10 17:18:07,574 com.binfoo.www.mvc.LogTimeProcessor.process(LogTimeProcessor.java:27) DEBUG - [POST]URI=/sysuser/login 46ms
2017-04-10 17:18:08,654 org.apache.shiro.web.servlet.SimpleCookie.readValue(SimpleCookie.java:389) DEBUG - Found 'JSESSIONID' cookie value [2b2ae48e-7e5d-4389-aab6-a81f6342bee5]
2017-04-10 17:18:08,654 org.nutz.mvc.impl.UrlMappingImpl.get(UrlMappingImpl.java:101) DEBUG - Found mapping for [GET] path=/sysuser/login : UserModule.loginPage(UserModule.java:203)
2017-04-10 17:18:08,655 org.nutz.ioc.impl.NutIoc.get(NutIoc.java:151) DEBUG - Get 'userModule'<class com.binfoo.www.module.UserModule>
2017-04-10 17:18:08,799 com.binfoo.www.mvc.LogTimeProcessor.process(LogTimeProcessor.java:27) DEBUG - [ GET]URI=/sysuser/login 144ms
2017-04-10 17:18:08,821 org.apache.shiro.web.servlet.SimpleCookie.readValue(SimpleCookie.java:389) DEBUG - Found 'JSESSIONID' cookie value [2b2ae48e-7e5d-4389-aab6-a81f6342bee5]
2017-04-10 17:18:08,822 org.nutz.mvc.impl.UrlMappingImpl.get(UrlMappingImpl.java:101) DEBUG - Found mapping for [GET] path=/captcha/next : CaptchaModule.next(CaptchaModule.java:26)
2017-04-10 17:18:08,823 org.nutz.ioc.impl.NutIoc.get(NutIoc.java:151) DEBUG - Get 'captchaModule'<class com.binfoo.www.module.CaptchaModule>
2017-04-10 17:18:08,850 com.binfoo.www.mvc.LogTimeProcessor.process(LogTimeProcessor.java:27) DEBUG - [ GET]URI=/captcha/next 28ms
2017-04-10 17:18:29,365 org.quartz.core.QuartzSchedulerThread.run(QuartzSchedulerThread.java:276) DEBUG - batch acquisition of 0 triggers
2017-04-10 17:18:52,779 org.quartz.core.QuartzSchedulerThread.run(QuartzSchedulerThread.java:276) DEBUG - batch acquisition of 0 triggers
2017-04-10 17:19:22,300 org.quartz.core.QuartzSchedulerThread.run(QuartzSchedulerThread.java:276) DEBUG - batch acquisition of 0 triggers
2017-04-10 17:19:49,337 org.quartz.core.QuartzSchedulerThread.run(QuartzSchedulerThread.java:276) DEBUG - batch acquisition of 1 triggers
2017-04-10 17:20:00,001 org.nutz.ioc.impl.NutIoc.get(NutIoc.java:151) DEBUG - Get 'cleanNonActiveUserJob'<class com.binfoo.www.quartz.job.CleanNonActiveUserJob>
2017-04-10 17:20:00,001 org.quartz.core.QuartzSchedulerThread.run(QuartzSchedulerThread.java:276) DEBUG - batch acquisition of 0 triggers
2017-04-10 17:20:00,002 org.quartz.core.JobRunShell.run(JobRunShell.java:201) DEBUG - Calling execute on job DEFAULT.com.binfoo.www.quartz.job.CleanNonActiveUserJob
2017-04-10 17:20:00,002 com.binfoo.www.quartz.job.CleanNonActiveUserJob.execute(CleanNonActiveUserJob.java:31) DEBUG - clean Non-Active User , start
2017-04-10 17:20:00,003 org.nutz.plugins.cache.dao.CachedNutDaoExecutor.exec(CachedNutDaoExecutor.java:147) DEBUG - sql = DELETE FROM t_user_profile WHERE uid>? AND ct<? AND (email_checked=? OR email IS NULL ), tables = [t_user_profile]
2017-04-10 17:20:00,004 org.nutz.dao.impl.sql.run.NutDaoExecutor.printSQL(NutDaoExecutor.java:388) DEBUG - DELETE FROM t_user_profile WHERE uid>? AND ct<? AND (email_checked=? OR email IS NULL )
    |  1 |                   2 |     3 |
    |----|---------------------|-------|
    | 10 | 2017-04-09 17:20:00 | false |
  For example:> "DELETE FROM t_user_profile WHERE uid>10 AND ct<'2017-04-09 17:20:00' AND (email_checked=false OR email IS NULL )"
2017-04-10 17:20:00,006 org.nutz.plugins.cache.dao.CachedNutDaoExecutor.exec(CachedNutDaoExecutor.java:194) DEBUG - Clear Cache=t_user_profile
2017-04-10 17:20:00,006 com.binfoo.www.quartz.job.CleanNonActiveUserJob.execute(CleanNonActiveUserJob.java:35) DEBUG - delete 0 UserProfile
2017-04-10 17:20:00,006 org.nutz.plugins.cache.dao.CachedNutDaoExecutor.exec(CachedNutDaoExecutor.java:147) DEBUG - sql = delete from t_user where id > 10 and not exists (select 1 from t_user_profile where t_user.id = uid ) and ct < ?, tables = [t_user, t_user_profile]
2017-04-10 17:20:00,007 org.nutz.dao.impl.sql.run.NutDaoExecutor.printSQL(NutDaoExecutor.java:388) DEBUG - delete from t_user where id > 10 and not exists (select 1 from t_user_profile where t_user.id = uid ) and ct < ?
    |                   1 |
    |---------------------|
    | 2017-04-09 17:20:00 |
  For example:> "delete from t_user where id > 10 and not exists (select 1 from t_user_profile where t_user.id = uid ) and ct < '2017-04-09 17:20:00'"
2017-04-10 17:20:00,009 org.nutz.plugins.cache.dao.CachedNutDaoExecutor.exec(CachedNutDaoExecutor.java:194) DEBUG - Clear Cache=t_user
2017-04-10 17:20:00,009 org.nutz.plugins.cache.dao.CachedNutDaoExecutor.exec(CachedNutDaoExecutor.java:194) DEBUG - Clear Cache=t_user_profile
2017-04-10 17:20:00,009 com.binfoo.www.quartz.job.CleanNonActiveUserJob.execute(CleanNonActiveUserJob.java:42) DEBUG - delete 0 User
2017-04-10 17:20:00,009 com.binfoo.www.quartz.job.CleanNonActiveUserJob.execute(CleanNonActiveUserJob.java:44) DEBUG - clean Non-Active User , Done
2017-04-10 17:20:25,397 org.quartz.core.QuartzSchedulerThread.run(QuartzSchedulerThread.java:276) DEBUG - batch acquisition of 0 triggers
2017-04-10 17:20:50,081 org.quartz.core.QuartzSchedulerThread.run(QuartzSchedulerThread.java:276) DEBUG - batch acquisition of 0 triggers
2017-04-10 17:20:56,026 org.apache.shiro.web.servlet.SimpleCookie.readValue(SimpleCookie.java:389) DEBUG - Found 'JSESSIONID' cookie value [ba393b70-c084-4215-83d0-ddc8ad3757a0]
2017-04-10 17:20:56,026 org.apache.shiro.mgt.DefaultSecurityManager.resolveSession(DefaultSecurityManager.java:447) DEBUG - Resolved SubjectContext context session is invalid.  Ignoring and creating an anonymous (session-less) Subject instance.
org.apache.shiro.session.UnknownSessionException: There is no session with id [ba393b70-c084-4215-83d0-ddc8ad3757a0]
	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:148)
	at org.apache.shiro.session.mgt.AbstractNativeSessionManager.getSession(AbstractNativeSessionManager.java:140)
	at org.apache.shiro.mgt.SessionsSecurityManager.getSession(SessionsSecurityManager.java:156)
	at org.apache.shiro.mgt.DefaultSecurityManager.resolveContextSession(DefaultSecurityManager.java:456)
	at org.apache.shiro.mgt.DefaultSecurityManager.resolveSession(DefaultSecurityManager.java:442)
	at org.apache.shiro.mgt.DefaultSecurityManager.createSubject(DefaultSecurityManager.java:338)
	at org.apache.shiro.subject.Subject$Builder.buildSubject(Subject.java:846)
	at org.apache.shiro.web.subject.WebSubject$Builder.buildWebSubject(WebSubject.java:148)
	at org.apache.shiro.web.servlet.AbstractShiroFilter.createSubject(AbstractShiroFilter.java:292)
	at org.apache.shiro.web.servlet.AbstractShiroFilter.doFilterInternal(AbstractShiroFilter.java:359)
	at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:212)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:141)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
	at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:522)
	at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1095)
	at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:672)
	at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.doRun(AprEndpoint.java:2500)
	at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.run(AprEndpoint.java:2489)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
	at java.lang.Thread.run(Thread.java:745)



具体登陆方法代码

 @At
    @Aop("redis")
    public Object login(@Param("username") String username, @Param("password") String password,
                        @Param("captcha") String captcha,
                        @Attr(scope = Scope.SESSION, value = "nutz_captcha") String _captcha, HttpSession session
    ) {
        NutMap re = new NutMap();
        if (!Toolkit.checkCaptcha(_captcha, captcha)) {
            return re.setv("ok", false).setv("msg", "验证码错误");
        }


        int userId = userService.fetch(username, password);
        if (userId < 0) {
            return re.setv("ok", false).setv("msg", "用户名或密码错误");
        } else {

//            Redis GETSET命令在Redis键中设置指定的字符串值,并返回其旧值。
//
//            返回值
//
//            返回一个字符串,也就是键的旧值。 如果键不存在,则返回nil。


            String oldSessionId = jedis().getSet("u:sid:" + userId, session.getId());


            System.out.println("sessionId = " + session.getId() + "and oldSessionId = " + oldSessionId);


            if (oldSessionId != null && oldSessionId != session.getId()) {

                //取出来老的sessionId,然后注销掉,新登陆的踢掉老的用户

                new Subject.Builder().sessionId(oldSessionId).buildSubject().logout();
            }

            // 完成nutdao_realm后启用.
            SecurityUtils.getSubject().login(new SimpleShiroToken(userId));
            //当前用户登录

//            subject.getSession().setAttribute("me", userId);

            return re.setv("ok", true);
        }
    }

try catch一下嘛 , 老session 已经过期的话, 自然会抛错.

try {
    new Subject.Builder().sessionId(oldSessionId).buildSubject().logout();
} catch (Exception) {}

老session默认多久到期

看你shiro.ini的配置了

没有用,还是一样的错误

哪一行报错

PS: oldSessionId != session.getId() 字符串要用equal

哎,我发现没有用,我是用的nutzbook教程练习的,集成了shiro的权限,貌似shiro 的session是缓存在ehcache里面的,这样我把session又缓存到redis,使用new Subject.Builder().sessionId(oldSessionId).buildSubject().logout();这个踢出去,实际上没啥用。。。

就是我用360浏览器登录,然后进行查看用户列表,同时我用ie浏览器继续登陆,如果正确的话,360的应该被踢出,可实际上360浏览器还是可以继续工作。。。

分步排查嘛:

首先, A浏览器登录, 得到session id, 检查redis内的值是否正确

然后, B浏览器登录, login方法开debug或者打印日志, 观察B浏览器的session id, 及redis中读取到的老session id

如果老session id, 也就是A浏览器的id被正确读取出来, 那就是要看 "new Subject.Builder().sessionId(oldSessionId)" 是否正常的, 因为能拿到session 才能logout

我设计了一个测试方法, 用于验证: 根据一个session id, 将其所属的session注销掉

	@Filters
	@At
	@Ok("raw")
	public String seid(HttpSession session) {
	    return session.getId() + "," + SecurityUtils.getSubject().isAuthenticated();
	}
	
    @Filters
    @At("/logout/?")
    @Ok("http:200")
    public void logoutBySeid(String seid) {
        new Subject.Builder().sessionId(seid).buildSubject().logout();
    }

浏览器分别是 Chrome 和 Firefox的最新版, 他们肯定不会共享cookie了

然后, 使用Chrome浏览器进行登录, 完成后访问

http://127.0.0.1:8080/nutzcn/user/seid

显示为:
r50n4677e0jkjpi5fqtkq5umnd,true

其中 r50n4677e0jkjpi5fqtkq5umnd 是session id, 后面是登录状态,为true,代表已经登录

然后使用Firefox浏览器, 访问

http://127.0.0.1:8080/nutzcn/user/logout/r50n4677e0jkjpi5fqtkq5umnd

页面无显示, 因为没东西, 后台也没有报错.

再使用Chrome访问

http://127.0.0.1:8080/nutzcn/user/seid

// 显示的内容是
66s1gij97gjmarjot93g8qrp40,false

// session id变了, 登录状态也变成未登录
// 再访问其他需要登录的页面,也跳到了登录页

所以, 根据上面的测试, 使用session id是可以把所属的session注销掉的

1,进行登录,显示登陆成功,然后同一个浏览器进行验证
98763A88673AC166B99A83EFD810A771,false,直接失败。。。
什么鬼
2,按照上面的方法,用另外一个非登陆浏览器进行退出session

请求的路径: /sysuser/logout/98763A88673AC166B99A83EFD810A771

异常堆栈如下:

        
java.lang.IllegalArgumentException: SessionKey must be an HTTP compatible implementation.
	at org.apache.shiro.web.session.mgt.ServletContainerSessionManager.getSession(ServletContainerSessionManager.java:70)
	at org.apache.shiro.mgt.SessionsSecurityManager.getSession(SessionsSecurityManager.java:156)
	at org.apache.shiro.mgt.DefaultSecurityManager.resolveContextSession(DefaultSecurityManager.java:456)
	at org.apache.shiro.mgt.DefaultSecurityManager.resolveSession(DefaultSecurityManager.java:442)
	at org.apache.shiro.mgt.DefaultSecurityManager.createSubject(DefaultSecurityManager.java:338)
	at org.apache.shiro.subject.Subject$Builder.buildSubject(Subject.java:846)
	at com.binfoo.www.module.UserModule.logoutBySeid(UserModule.java:54)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:497)
	at org.nutz.mvc.impl.processor.MethodInvokeProcessor.process(MethodInvokeProcessor.java:25)
	at org.nutz.mvc.impl.processor.AbstractProcessor.doNext(AbstractProcessor.java:44)
	at org.nutz.mvc.impl.processor.AdaptorProcessor.process(AdaptorProcessor.java:33)
	at org.nutz.mvc.impl.processor.AbstractProcessor.doNext(AbstractProcessor.java:44)
	at org.nutz.mvc.impl.processor.ActionFiltersProcessor.process(ActionFiltersProcessor.java:58)
	at org.nutz.mvc.impl.processor.AbstractProcessor.doNext(AbstractProcessor.java:44)
	at org.nutz.integration.shiro.NutShiroProcessor.process(NutShiroProcessor.java:126)
	at org.nutz.mvc.impl.processor.AbstractProcessor.doNext(AbstractProcessor.java:44)
	at org.nutz.mvc.impl.processor.ModuleProcessor.process(ModuleProcessor.java:123)
	at org.nutz.mvc.impl.processor.AbstractProcessor.doNext(AbstractProcessor.java:44)
	at org.nutz.mvc.impl.processor.EncodingProcessor.process(EncodingProcessor.java:27)
	at org.nutz.mvc.impl.processor.AbstractProcessor.doNext(AbstractProcessor.java:44)
	at org.nutz.mvc.impl.processor.UpdateRequestAttributesProcessor.process(UpdateRequestAttributesProcessor.java:15)
	at org.nutz.mvc.impl.processor.AbstractProcessor.doNext(AbstractProcessor.java:44)
	at com.binfoo.www.mvc.LogTimeProcessor.process(LogTimeProcessor.java:22)
	at org.nutz.mvc.impl.NutActionChain.doChain(NutActionChain.java:44)
	at org.nutz.mvc.impl.ActionInvoker.invoke(ActionInvoker.java:67)
	at org.nutz.mvc.ActionHandler.handle(ActionHandler.java:31)
	at org.nutz.mvc.NutFilter.doFilter(NutFilter.java:198)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
	at com.alibaba.druid.support.http.WebStatFilter.doFilter(WebStatFilter.java:123)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
	at org.apache.shiro.web.servlet.AbstractShiroFilter.executeChain(AbstractShiroFilter.java:449)
	at org.apache.shiro.web.servlet.AbstractShiroFilter$1.call(AbstractShiroFilter.java:365)
	at org.apache.shiro.subject.support.SubjectCallable.doCall(SubjectCallable.java:90)
	at org.apache.shiro.subject.support.SubjectCallable.call(SubjectCallable.java:83)
	at org.apache.shiro.subject.support.DelegatingSubject.execute(DelegatingSubject.java:383)
	at org.apache.shiro.web.servlet.AbstractShiroFilter.doFilterInternal(AbstractShiroFilter.java:362)
	at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:212)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:141)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
	at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:522)
	at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1095)
	at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:672)
	at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.doRun(AprEndpoint.java:2500)
	at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.run(AprEndpoint.java:2489)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
	at java.lang.Thread.run(Thread.java:745)

要疯。。。

所有代码贴出来

package com.binfoo.www.module;

import javax.servlet.http.HttpSession;

import com.binfoo.www.bean.User;
import com.binfoo.www.bean.UserProfile;
import com.binfoo.www.service.UserService;
import com.binfoo.www.util.Toolkit;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.subject.Subject;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Cnd;
import org.nutz.dao.QueryResult;
import org.nutz.dao.pager.Pager;
import org.nutz.integration.shiro.SimpleShiroToken;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Strings;
import org.nutz.lang.util.NutMap;
import org.nutz.log.Log;
import org.nutz.log.Logs;
import org.nutz.mvc.Scope;
import org.nutz.mvc.annotation.*;


import static org.nutz.integration.jedis.RedisInterceptor.jedis;

@IocBean // 声明为Ioc容器中的一个Bean
@At("/sysuser") // 整个模块的路径前缀
@Ok("json:{locked:'password|salt',ignoreNull:true}") // 忽略password和salt属性,忽略空属性的json输出
@Fail("http:500") // 抛出异常的话,就走500页面
public class UserModule extends BaseModule {

    private static final Log log = Logs.get();

    private static final int MAX_USER_ONLINE = 2;

    @Inject
    protected UserService userService;

    @Filters
    @At
    @Ok("raw")
    public String seid(HttpSession session) {
        return session.getId() + "," + SecurityUtils.getSubject().isAuthenticated();
    }

    @Filters
    @At("/logout/?")
    @Ok("http:200")
    public void logoutBySeid(String seid) {
        new Subject.Builder().sessionId(seid).buildSubject().logout();
    }


    @At
    public int count() { // 统计用户数的方法,算是个测试点
        return dao.count(User.class);
    }

    // 不允许后者登录
//        Long re = jedis().setnx("u:sid:"+uid, sessionid);
//        if (re == 0) {
//            // 老session id存在, 检查一下是否过期. 如果没过期, 拒绝登录
//        }
//        shiro.login(...);
//        String oldSessionId = jedis().getSet("u:sid:"+uid, sessionid);
//        if (oldSessionId != null) {
//            // 老session id存在, 取出session, 注销掉
//        }
//        shiro.login(...);

    @At
    @Aop("redis")
    public Object login(@Param("username") String username, @Param("password") String password,
                        @Param("captcha") String captcha,
                        @Attr(scope = Scope.SESSION, value = "nutz_captcha") String _captcha, HttpSession session
    ) {
        NutMap re = new NutMap();
        if (!Toolkit.checkCaptcha(_captcha, captcha)) {
            return re.setv("ok", false).setv("msg", "验证码错误");
        }

        int userId = userService.fetch(username, password);

        try {


            if (userId < 0) {
                return re.setv("ok", false).setv("msg", "用户名或密码错误");
            } else {

//            Redis GETSET命令在Redis键中设置指定的字符串值,并返回其旧值。
//
//            返回值
//
//            返回一个字符串,也就是键的旧值。 如果键不存在,则返回nil。


                String oldSessionId = jedis().getSet("u:sid:" + userId, session.getId());


                log.info("sessionId = " + session.getId() + " ======== and oldSessionId = " + oldSessionId);


                if (oldSessionId != null && !oldSessionId.equalsIgnoreCase(session.getId())) {

                    //取出来老的sessionId,然后注销掉,新登陆的踢掉老的用户

                    new Subject.Builder().sessionId(oldSessionId).buildSubject().logout();

                }

                // 完成nutdao_realm后启用.
                SecurityUtils.getSubject().login(new SimpleShiroToken(userId));
                //当前用户登录

                session.setAttribute("me", userId);
            }


        } catch (Exception e) {
            log.debug("老的会话已经过期");
            session.setAttribute("me", userId);
            return re.setv("ok", true);
        }

        return re.setv("ok", true);

    }

    @At
    @Ok(">>:/") // 跟其他方法不同,这个方法完成后就跳转首页了
    public void logout(HttpSession session) {
        session.invalidate();
    }

    @At
    @RequiresPermissions("sysuser:add")
    public Object add(@Param("..") User user) { // 两个点号是按对象属性一一设置
        NutMap re = new NutMap();
        String msg = checkUser(user, true);
        if (msg != null) {
            return re.setv("ok", false).setv("msg", msg);
        }

        user = userService.add(user.getName(), user.getPassword());
        return re.setv("ok", true).setv("data", user);
    }

    @At
    @RequiresPermissions("sysuser:update")
    public Object update(@Param("password") String password, @Attr("me") int me) {
        if (Strings.isBlank(password) || password.length() < 6)
            return new NutMap().setv("ok", false).setv("msg", "密码不符合要求");
        userService.updatePassword(me, password);
        return new NutMap().setv("ok", true);
    }

    @At
    @Aop(TransAop.READ_COMMITTED)
    @RequiresPermissions("sysuser:delete")
    public Object delete(@Param("id") int id, @Attr("me") int me) {
        if (me == id) {
            return new NutMap().setv("ok", false).setv("msg", "不能删除当前用户!!");
        }
        dao.delete(User.class, id); // 再严谨一些的话,需要判断是否为>0
        dao.clear(UserProfile.class, Cnd.where("userId", "=", me));
        return new NutMap().setv("ok", true);
    }

    @At
//    @RequiresPermissions("sysuser:query")
    public Object query(@Param("name") String name, @Param("..") Pager pager) {
        Cnd cnd = Strings.isBlank(name) ? null : Cnd.where("name", "like", "%" + name + "%");
        QueryResult qr = new QueryResult();
        qr.setList(dao.query(User.class, cnd, pager));
        pager.setRecordCount(dao.count(User.class, cnd));
        qr.setPager(pager);
        return qr; //默认分页是第1页,每页20条
    }

    @At("/")
//    @RequiresPermissions("sysuser:index")
    @Ok("jsp:jsp.user.list") // 真实路径是 /WEB-INF/jsp/user/list.jsp
    public void index() {

    }

    protected String checkUser(User user, boolean create) {
        if (user == null) {
            return "空对象";
        }
        if (create) {
            if (Strings.isBlank(user.getName()) || Strings.isBlank(user.getPassword()))
                return "用户名/密码不能为空";
        } else {
            if (Strings.isBlank(user.getPassword()))
                return "密码不能为空";
        }
        String passwd = user.getPassword().trim();
        if (6 > passwd.length() || passwd.length() > 12) {
            return "密码长度错误";
        }
        user.setPassword(passwd);
        if (create) {
            int count = dao.count(User.class, Cnd.where("name", "=", user.getName()));
            if (count != 0) {
                return "用户名已经存在";
            }
        } else {
            if (user.getId() < 1) {
                return "用户Id非法";
            }
        }
        if (user.getName() != null)
            user.setName(user.getName().trim());
        return null;
    }

    @GET
    @At("/login")
    @Ok("jsp:jsp.user.login") // 将内部重定向到登录jsp
    public void loginPage() {
    }
}

这句要单独try catch的. 不然老session id有任何异常,新的session都不可能登录成功

try {
    new Subject.Builder().sessionId(oldSessionId).buildSubject().logout();
} catch (Exception) {}

true可以了,退出的时候报错
应该是seid类型我看shiro是序列化的,我用string是错的
要怎么转换

java.lang.IllegalArgumentException: SessionKey must be an HTTP compatible implementation.
	at org.apache.shiro.web.session.mgt.ServletContainerSessionManager.getSession(ServletContainerSessionManager.java:70)
	at org.apache.shiro.mgt.SessionsSecurityManager.getSession(SessionsSecurityManager.java:156)
	at org.apache.shiro.mgt.DefaultSecurityManager.resolveContextSession(DefaultSecurityManager.java:456)
	at org.apache.shiro.mgt.DefaultSecurityManager.resolveSession(DefaultSecurityManager.java:442)
	at org.apache.shiro.mgt.DefaultSecurityManager.createSubject(DefaultSecurityManager.java:338)
	at org.apache.shiro.subject.Subject$Builder.buildSubject(Subject.java:846)
	at com.binfoo.www.module.UserModule.logoutBySeid(UserModule.java:56)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:497)
	at org.nutz.mvc.impl.processor.MethodInvokeProcessor.process(MethodInvokeProcessor.java:25)
	at org.nutz.mvc.impl.processor.AbstractProcessor.doNext(AbstractProcessor.java:44)
	at org.nutz.mvc.impl.processor.AdaptorProcessor.process(AdaptorProcessor.java:33)
	at org.nutz.mvc.impl.processor.AbstractProcessor.doNext(AbstractProcessor.java:44)
	at org.nutz.mvc.impl.processor.ActionFiltersProcessor.process(ActionFiltersProcessor.java:58)
	at org.nutz.mvc.impl.processor.AbstractProcessor.doNext(AbstractProcessor.java:44)
	at org.nutz.integration.shiro.NutShiroProcessor.process(NutShiroProcessor.java:126)
	at org.nutz.mvc.impl.processor.AbstractProcessor.doNext(AbstractProcessor.java:44)
	at org.nutz.mvc.impl.processor.ModuleProcessor.process(ModuleProcessor.java:123)
	at org.nutz.mvc.impl.processor.AbstractProcessor.doNext(AbstractProcessor.java:44)
	at org.nutz.mvc.impl.processor.EncodingProcessor.process(EncodingProcessor.java:27)
	at org.nutz.mvc.impl.processor.AbstractProcessor.doNext(AbstractProcessor.java:44)
	at org.nutz.mvc.impl.processor.UpdateRequestAttributesProcessor.process(UpdateRequestAttributesProcessor.java:15)
	at org.nutz.mvc.impl.processor.AbstractProcessor.doNext(AbstractProcessor.java:44)
	at com.binfoo.www.mvc.LogTimeProcessor.process(LogTimeProcessor.java:22)
	at org.nutz.mvc.impl.NutActionChain.doChain(NutActionChain.java:44)
	at org.nutz.mvc.impl.ActionInvoker.invoke(ActionInvoker.java:67)
	at org.nutz.mvc.ActionHandler.handle(ActionHandler.java:31)
	at org.nutz.mvc.NutFilter.doFilter(NutFilter.java:198)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
	at com.alibaba.druid.support.http.WebStatFilter.doFilter(WebStatFilter.java:123)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
	at org.apache.shiro.web.servlet.AbstractShiroFilter.executeChain(AbstractShiroFilter.java:449)
	at org.apache.shiro.web.servlet.AbstractShiroFilter$1.call(AbstractShiroFilter.java:365)
	at org.apache.shiro.subject.support.SubjectCallable.doCall(SubjectCallable.java:90)
	at org.apache.shiro.subject.support.SubjectCallable.call(SubjectCallable.java:83)
	at org.apache.shiro.subject.support.DelegatingSubject.execute(DelegatingSubject.java:383)
	at org.apache.shiro.web.servlet.AbstractShiroFilter.doFilterInternal(AbstractShiroFilter.java:362)
	at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:212)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:141)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
	at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:522)
	at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1095)
	at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:672)
	at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.doRun(AprEndpoint.java:2500)
	at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.run(AprEndpoint.java:2489)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
	at java.lang.Thread.run(Thread.java:745)

shiro.ini 贴一下, 感觉你用的是容器原生session

[main]
nutzdao_realm = com.binfoo.www.shiro.realm.SimpleAuthorizingRealm
cacheManager = org.apache.shiro.cache.ehcache.EhCacheManager
cacheManager.cacheManagerConfigFile = classpath:ehcache.xml
nutzdao_realm.cacheManager = $cacheManager

authc = org.nutz.integration.shiro.SimpleAuthenticationFilter
authc.loginUrl = /sysuser/login
logout.redirectUrl = /sysuser/login

[urls]
/rs/* = anon, noSessionCreation
/sysuser/logout = logout
/sysuser/error = anon
/sysuser/login = anon
/sysuser/profile/active/mail = anon

恩? 你不是说用了ehcache和redis吗? shiro.ini没这么少吧?

var ioc = {
    // "cacheManager" : {
    //     "type" : "net.sf.ehcache.CacheManager",
    //     "factory" : "net.sf.ehcache.CacheManager#getCacheManager",
    //     "args" : ["bms"] // 对应shiro.ini中指定的ehcache.xml中定义的name
    // }
     // 如果不需要shiro初始化的Ehcache, 使用下面的方式配置
     "cacheManager" : {
     "type" : "net.sf.ehcache.CacheManager",
     "factory" : "net.sf.ehcache.CacheManager#create"
     }
};

<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="ehcache.xsd" updateCheck="false" monitoring="autodetect" dynamicConfig="true" name="bms"> <!-- <diskStore path="java.io.tmpdir/shiro-ehcache"/> --> <defaultCache maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="false" diskPersistent="false" diskExpiryThreadIntervalSeconds="120" /> <cache name="shiro-activeSessionCache" maxElementsInMemory="10000" overflowToDisk="true" eternal="true" timeToLiveSeconds="0" timeToIdleSeconds="0" diskPersistent="true" diskExpiryThreadIntervalSeconds="600"/> </ehcache>

额,要都配上?我按照nutzbook来的

shiro版本差异? 先不管了. 既然它要求"SessionKey must be an HTTP compatible implementation", 那就给它个合法的:

new Subject.Builder().sessionId(new WebSessionKey(oldSessionId, Mvcs.getReq(), Mvcs.getResp())).buildSubject().logout();

    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-core</artifactId>
        <version>1.3.2</version>
    </dependency>


    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-ehcache</artifactId>
        <version>1.2.3</version>
    </dependency>

依然报错,兽总辛苦

package com.binfoo.www.module;

import javax.servlet.http.HttpSession;

import com.binfoo.www.bean.User;
import com.binfoo.www.bean.UserProfile;
import com.binfoo.www.service.UserService;
import com.binfoo.www.util.Toolkit;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.session.mgt.WebSessionKey;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Cnd;
import org.nutz.dao.QueryResult;
import org.nutz.dao.pager.Pager;
import org.nutz.integration.shiro.SimpleShiroToken;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Strings;
import org.nutz.lang.util.NutMap;
import org.nutz.log.Log;
import org.nutz.log.Logs;
import org.nutz.mvc.Mvcs;
import org.nutz.mvc.Scope;
import org.nutz.mvc.annotation.*;


import java.io.Serializable;

import static org.nutz.integration.jedis.RedisInterceptor.jedis;

@IocBean // 声明为Ioc容器中的一个Bean
@At("/sysuser") // 整个模块的路径前缀
@Ok("json:{locked:'password|salt',ignoreNull:true}") // 忽略password和salt属性,忽略空属性的json输出
@Fail("http:500") // 抛出异常的话,就走500页面
public class UserModule extends BaseModule {

    private static final Log log = Logs.get();

    private static final int MAX_USER_ONLINE = 2;

    @Inject
    protected UserService userService;

    @Filters
    @At
    @Ok("raw")
    public String seid(HttpSession session) {
        return session.getId() + "," + SecurityUtils.getSubject().isAuthenticated();
    }

    @Filters
    @At("/forcelogout/?")
    @Ok("http:200")
    public void logoutBySeid(String seid) {
        new Subject.Builder().sessionId(new WebSessionKey(seid, Mvcs.getReq(), Mvcs.getResp())).buildSubject().logout();
    }


    @At
    public int count() { // 统计用户数的方法,算是个测试点
        return dao.count(User.class);
    }

    // 不允许后者登录
//        Long re = jedis().setnx("u:sid:"+uid, sessionid);
//        if (re == 0) {
//            // 老session id存在, 检查一下是否过期. 如果没过期, 拒绝登录
//        }
//        shiro.login(...);
//        String oldSessionId = jedis().getSet("u:sid:"+uid, sessionid);
//        if (oldSessionId != null) {
//            // 老session id存在, 取出session, 注销掉
//        }
//        shiro.login(...);

    @At
    @Aop("redis")
    public Object login(@Param("username") String username, @Param("password") String password,
                        @Param("captcha") String captcha,
                        @Attr(scope = Scope.SESSION, value = "nutz_captcha") String _captcha, HttpSession session
    ) {
        NutMap re = new NutMap();
        if (!Toolkit.checkCaptcha(_captcha, captcha)) {
            return re.setv("ok", false).setv("msg", "验证码错误");
        }

        int userId = userService.fetch(username, password);


        if (userId < 0) {
            return re.setv("ok", false).setv("msg", "用户名或密码错误");
        } else {

//            Redis GETSET命令在Redis键中设置指定的字符串值,并返回其旧值。
//
//            返回值
//
//            返回一个字符串,也就是键的旧值。 如果键不存在,则返回nil。


            String oldSessionId = jedis().getSet("u:sid:" + userId, session.getId());


            log.info("sessionId = " + session.getId() + " ======== and oldSessionId = " + oldSessionId);


            if (oldSessionId != null && !oldSessionId.equalsIgnoreCase(session.getId())) {

                //取出来老的sessionId,然后注销掉,新登陆的踢掉老的用户


                try {
//                    new Subject.Builder().sessionId(oldSessionId).buildSubject().logout();

                    new Subject.Builder().sessionId(new WebSessionKey(oldSessionId, Mvcs.getReq(), Mvcs.getResp())).buildSubject().logout();

                } catch (Exception e) {

                }


            }

            // 完成nutdao_realm后启用.
            SecurityUtils.getSubject().login(new SimpleShiroToken(userId));
            //当前用户登录

            session.setAttribute("me", userId);
        }


        return re.setv("ok", true);

    }

    @At
    @Ok(">>:/") // 跟其他方法不同,这个方法完成后就跳转首页了
    public void logout(HttpSession session) {
        session.invalidate();
    }

    @At
    @RequiresPermissions("sysuser:add")
    public Object add(@Param("..") User user) { // 两个点号是按对象属性一一设置
        NutMap re = new NutMap();
        String msg = checkUser(user, true);
        if (msg != null) {
            return re.setv("ok", false).setv("msg", msg);
        }

        user = userService.add(user.getName(), user.getPassword());
        return re.setv("ok", true).setv("data", user);
    }

    @At
    @RequiresPermissions("sysuser:update")
    public Object update(@Param("password") String password, @Attr("me") int me) {
        if (Strings.isBlank(password) || password.length() < 6)
            return new NutMap().setv("ok", false).setv("msg", "密码不符合要求");
        userService.updatePassword(me, password);
        return new NutMap().setv("ok", true);
    }

    @At
    @Aop(TransAop.READ_COMMITTED)
    @RequiresPermissions("sysuser:delete")
    public Object delete(@Param("id") int id, @Attr("me") int me) {
        if (me == id) {
            return new NutMap().setv("ok", false).setv("msg", "不能删除当前用户!!");
        }
        dao.delete(User.class, id); // 再严谨一些的话,需要判断是否为>0
        dao.clear(UserProfile.class, Cnd.where("userId", "=", me));
        return new NutMap().setv("ok", true);
    }

    @At
//    @RequiresPermissions("sysuser:query")
    public Object query(@Param("name") String name, @Param("..") Pager pager) {
        Cnd cnd = Strings.isBlank(name) ? null : Cnd.where("name", "like", "%" + name + "%");
        QueryResult qr = new QueryResult();
        qr.setList(dao.query(User.class, cnd, pager));
        pager.setRecordCount(dao.count(User.class, cnd));
        qr.setPager(pager);
        return qr; //默认分页是第1页,每页20条
    }

    @At("/")
//    @RequiresPermissions("sysuser:index")
    @Ok("jsp:jsp.user.list") // 真实路径是 /WEB-INF/jsp/user/list.jsp
    public void index() {

    }

    protected String checkUser(User user, boolean create) {
        if (user == null) {
            return "空对象";
        }
        if (create) {
            if (Strings.isBlank(user.getName()) || Strings.isBlank(user.getPassword()))
                return "用户名/密码不能为空";
        } else {
            if (Strings.isBlank(user.getPassword()))
                return "密码不能为空";
        }
        String passwd = user.getPassword().trim();
        if (6 > passwd.length() || passwd.length() > 12) {
            return "密码长度错误";
        }
        user.setPassword(passwd);
        if (create) {
            int count = dao.count(User.class, Cnd.where("name", "=", user.getName()));
            if (count != 0) {
                return "用户名已经存在";
            }
        } else {
            if (user.getId() < 1) {
                return "用户Id非法";
            }
        }
        if (user.getName() != null)
            user.setName(user.getName().trim());
        return null;
    }

    @GET
    @At("/login")
    @Ok("jsp:jsp.user.login") // 将内部重定向到登录jsp
    public void loginPage() {
    }
}

shiro-ehcach的版本与shiro-core对不上

前面版本对不上,现在的maven改了

2017-04-11 09:05:08,895 org.nutz.mvc.impl.processor.FailProcessor.process(FailProcessor.java:28) WARN  - Error@/sysuser/forcelogout/118E5A81FE10728451821CD7F3566116 :
java.lang.IllegalArgumentException: SessionKey must be an HTTP compatible implementation.
	at org.apache.shiro.web.session.mgt.ServletContainerSessionManager.getSession(ServletContainerSessionManager.java:70)
	at org.apache.shiro.mgt.SessionsSecurityManager.getSession(SessionsSecurityManager.java:156)
	at org.apache.shiro.mgt.DefaultSecurityManager.resolveContextSession(DefaultSecurityManager.java:456)
	at org.apache.shiro.mgt.DefaultSecurityManager.resolveSession(DefaultSecurityManager.java:442)
	at org.apache.shiro.mgt.DefaultSecurityManager.createSubject(DefaultSecurityManager.java:338)
	at org.apache.shiro.subject.Subject$Builder.buildSubject(Subject.java:846)
	at com.binfoo.www.module.UserModule.logoutBySeid(UserModule.java:60)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:497)
	at org.nutz.mvc.impl.processor.MethodInvokeProcessor.process(MethodInvokeProcessor.java:25)
	at org.nutz.mvc.impl.processor.AbstractProcessor.doNext(AbstractProcessor.java:44)
	at org.nutz.mvc.impl.processor.AdaptorProcessor.process(AdaptorProcessor.java:33)
	at org.nutz.mvc.impl.processor.AbstractProcessor.doNext(AbstractProcessor.java:44)
	at org.nutz.mvc.impl.processor.ActionFiltersProcessor.process(ActionFiltersProcessor.java:58)
	at org.nutz.mvc.impl.processor.AbstractProcessor.doNext(AbstractProcessor.java:44)
	at org.nutz.integration.shiro.NutShiroProcessor.process(NutShiroProcessor.java:126)
	at org.nutz.mvc.impl.processor.AbstractProcessor.doNext(AbstractProcessor.java:44)
	at org.nutz.mvc.impl.processor.ModuleProcessor.process(ModuleProcessor.java:123)
	at org.nutz.mvc.impl.processor.AbstractProcessor.doNext(AbstractProcessor.java:44)
	at org.nutz.mvc.impl.processor.EncodingProcessor.process(EncodingProcessor.java:27)
	at org.nutz.mvc.impl.processor.AbstractProcessor.doNext(AbstractProcessor.java:44)
	at org.nutz.mvc.impl.processor.UpdateRequestAttributesProcessor.process(UpdateRequestAttributesProcessor.java:15)
	at org.nutz.mvc.impl.processor.AbstractProcessor.doNext(AbstractProcessor.java:44)
	at com.binfoo.www.mvc.LogTimeProcessor.process(LogTimeProcessor.java:22)
	at org.nutz.mvc.impl.NutActionChain.doChain(NutActionChain.java:44)
	at org.nutz.mvc.impl.ActionInvoker.invoke(ActionInvoker.java:67)
	at org.nutz.mvc.ActionHandler.handle(ActionHandler.java:31)
	at org.nutz.mvc.NutFilter.doFilter(NutFilter.java:198)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
	at com.alibaba.druid.support.http.WebStatFilter.doFilter(WebStatFilter.java:123)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
	at org.apache.shiro.web.servlet.AbstractShiroFilter.executeChain(AbstractShiroFilter.java:449)
	at org.apache.shiro.web.servlet.AbstractShiroFilter$1.call(AbstractShiroFilter.java:365)
	at org.apache.shiro.subject.support.SubjectCallable.doCall(SubjectCallable.java:90)
	at org.apache.shiro.subject.support.SubjectCallable.call(SubjectCallable.java:83)
	at org.apache.shiro.subject.support.DelegatingSubject.execute(DelegatingSubject.java:383)
	at org.apache.shiro.web.servlet.AbstractShiroFilter.doFilterInternal(AbstractShiroFilter.java:362)
	at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:212)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:141)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
	at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:522)
	at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1095)
	at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:672)
	at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.doRun(AprEndpoint.java:2500)
	at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.run(AprEndpoint.java:2489)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
	at java.lang.Thread.run(Thread.java:745)

 <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-ehcache</artifactId>
            <version>1.3.2</version>
        </dependency>
 <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
            <version>1.3.2</version>
        </dependency>

@Filters
@At("/forcelogout/?")
@Ok("http:200")
public void logoutBySeid(String seid) {
// new Subject.Builder().sessionId(new WebSessionKey(seid, Mvcs.getReq(), Mvcs.getResp())).buildSubject().logout();

    new Subject.Builder().sessionId(seid).buildSubject().logout();
}

两种同样的错误

@binfoo 用WebSessionKey,贴它的出错信息

第58行对应
new Subject.Builder().sessionId(new WebSessionKey(seid, Mvcs.getReq(), Mvcs.getResp())).buildSubject().logout();

2017-04-11 09:12:20,510 com.binfoo.www.mvc.LogTimeProcessor.process(LogTimeProcessor.java:27) DEBUG - [ GET]URI=/sysuser/forcelogout/F575602A34199F7FE52F83EF891A0024 0ms
2017-04-11 09:12:20,510 org.nutz.mvc.impl.processor.FailProcessor.process(FailProcessor.java:28) WARN  - Error@/sysuser/forcelogout/F575602A34199F7FE52F83EF891A0024 :
java.lang.IllegalArgumentException: SessionKey must be an HTTP compatible implementation.
	at org.apache.shiro.web.session.mgt.ServletContainerSessionManager.getSession(ServletContainerSessionManager.java:70)
	at org.apache.shiro.mgt.SessionsSecurityManager.getSession(SessionsSecurityManager.java:156)
	at org.apache.shiro.mgt.DefaultSecurityManager.resolveContextSession(DefaultSecurityManager.java:456)
	at org.apache.shiro.mgt.DefaultSecurityManager.resolveSession(DefaultSecurityManager.java:442)
	at org.apache.shiro.mgt.DefaultSecurityManager.createSubject(DefaultSecurityManager.java:338)
	at org.apache.shiro.subject.Subject$Builder.buildSubject(Subject.java:846)
	at com.binfoo.www.module.UserModule.logoutBySeid(UserModule.java:58)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:497)
	at org.nutz.mvc.impl.processor.MethodInvokeProcessor.process(MethodInvokeProcessor.java:25)
	at org.nutz.mvc.impl.processor.AbstractProcessor.doNext(AbstractProcessor.java:44)
	at org.nutz.mvc.impl.processor.AdaptorProcessor.process(AdaptorProcessor.java:33)
	at org.nutz.mvc.impl.processor.AbstractProcessor.doNext(AbstractProcessor.java:44)
	at org.nutz.mvc.impl.processor.ActionFiltersProcessor.process(ActionFiltersProcessor.java:58)
	at org.nutz.mvc.impl.processor.AbstractProcessor.doNext(AbstractProcessor.java:44)
	at org.nutz.integration.shiro.NutShiroProcessor.process(NutShiroProcessor.java:126)
	at org.nutz.mvc.impl.processor.AbstractProcessor.doNext(AbstractProcessor.java:44)
	at org.nutz.mvc.impl.processor.ModuleProcessor.process(ModuleProcessor.java:123)
	at org.nutz.mvc.impl.processor.AbstractProcessor.doNext(AbstractProcessor.java:44)
	at org.nutz.mvc.impl.processor.EncodingProcessor.process(EncodingProcessor.java:27)
	at org.nutz.mvc.impl.processor.AbstractProcessor.doNext(AbstractProcessor.java:44)
	at org.nutz.mvc.impl.processor.UpdateRequestAttributesProcessor.process(UpdateRequestAttributesProcessor.java:15)
	at org.nutz.mvc.impl.processor.AbstractProcessor.doNext(AbstractProcessor.java:44)
	at com.binfoo.www.mvc.LogTimeProcessor.process(LogTimeProcessor.java:22)
	at org.nutz.mvc.impl.NutActionChain.doChain(NutActionChain.java:44)
	at org.nutz.mvc.impl.ActionInvoker.invoke(ActionInvoker.java:67)
	at org.nutz.mvc.ActionHandler.handle(ActionHandler.java:31)
	at org.nutz.mvc.NutFilter.doFilter(NutFilter.java:198)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
	at com.alibaba.druid.support.http.WebStatFilter.doFilter(WebStatFilter.java:123)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
	at org.apache.shiro.web.servlet.AbstractShiroFilter.executeChain(AbstractShiroFilter.java:449)
	at org.apache.shiro.web.servlet.AbstractShiroFilter$1.call(AbstractShiroFilter.java:365)
	at org.apache.shiro.subject.support.SubjectCallable.doCall(SubjectCallable.java:90)
	at org.apache.shiro.subject.support.SubjectCallable.call(SubjectCallable.java:83)
	at org.apache.shiro.subject.support.DelegatingSubject.execute(DelegatingSubject.java:383)
	at org.apache.shiro.web.servlet.AbstractShiroFilter.doFilterInternal(AbstractShiroFilter.java:362)
	at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:212)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:141)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
	at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:522)
	at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1095)
	at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:672)
	at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.doRun(AprEndpoint.java:2500)
	at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.run(AprEndpoint.java:2489)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
	at java.lang.Thread.run(Thread.java:745)
2017-04-11 09:12:24,317 org.quartz.core.QuartzSchedulerThread.run(QuartzSchedulerThread.java:276) DEBUG - batch acquisition of 0 triggers
2017-04-11 09:12:47,448 org.quartz.core.QuartzSchedulerThread.run(QuartzSchedulerThread.java:276) DEBUG - batch acquisition of 0 triggers

既然这样, debug一下ServletContainerSessionManager.getSession方法, 看看key倒是是啥类型,为啥报错

已经在群里截图

换个思路

问题出在ServletContainerSessionManager, 而这个用的是 容器Session, 那我们换掉它

http://shiro.apache.org/web.html#native-sessions

[main]
# 加这句
sessionManager = org.apache.shiro.web.session.mgt.DefaultWebSessionManager

然后,sessionId用回字符串, 不走WebSessionId了

 public void logoutBySeid(String seid) {
    new Subject.Builder().sessionId(seid).buildSubject().logout();
}

加2行才对

[main]
sessionManager = org.apache.shiro.web.session.mgt.DefaultWebSessionManager
# configure properties (like session timeout) here if desired

# Use the configured native session manager:
securityManager.sessionManager = $sessionManager

不纠结了,我先学习下兽总的nutz.cn

添加回复
请先登陆
回到顶部