使用框架:Shiro+SpringBoot
首先,我先说步骤:
1.登陆
3.将已登陆用户踢出,自己登陆。
这只是说原理,具体实现现在说。
踢出已登陆用户,主要体现在对已登陆用户session的处理上,原理简单,就是将已登陆用户的session删除就好。
难点在于如何找到该用户的session。
这里,我使用了redis
首先,在登陆的时候获取用户的sessionId,也就是浏览器中的jessionId,因为我使用的是shiro框架,方法如下:Subject user = SecurityUtils.getSubject(); UsernamePasswordToken token = new UsernamePasswordToken(phone, MD5Utils.getMD5Str(password).toCharArray()); //DigestUtils.md5Hex(password).toCharArray());// token.setRememberMe(true); try { user.login(token); user.getSession().setTimeout(-1000L); // 开发时设置永不过期,上线时需要调整 todo } catch (UnknownAccountException e) { logger.error("账号不存在:{}", e); return new ChariotResponseEntity<>(ChariotHttpStatus.USER_ACCOUNT_OR_PASSWORD_ERROR); } catch (DisabledAccountException e) { logger.error("账号未启用:{}", e); return new ChariotResponseEntity<>(ChariotHttpStatus.USER_NOT_ENABLED); } catch (IncorrectCredentialsException e) { logger.error("密码错误:{}", e); return new ChariotResponseEntity<>(ChariotHttpStatus.USER_ACCOUNT_OR_PASSWORD_ERROR); } catch (RuntimeException e) { logger.error("未知错误,请联系管理员:{}" + e.toString(), e); System.out.println(e.toString()); return new ChariotResponseEntity<>(ChariotHttpStatus.USER_OTHER_REASON); } SessionsSecurityManager securityManager = (SessionsSecurityManager) SecurityUtils.getSecurityManager(); DefaultSessionManager sessionManager = (DefaultSessionManager) securityManager.getSessionManager(); String sessionId = String.valueOf(user.getSession().getId());
主要是其中这段SessionsSecurityManager securityManager = (SessionsSecurityManager) SecurityUtils.getSecurityManager(); DefaultSessionManager sessionManager = (DefaultSessionManager) securityManager.getSessionManager(); String sessionId = String.valueOf(user.getSession().getId());
拿到当前登陆用户的sessionId之后,就该获取存入redis中的在这之前登陆的用户的sessionId,
这里我要解释一下sessionId的存取的现实操作步骤:
(背景:A用户没有登陆。)
1.A用户登陆,并获取A用户的sessionIdSubject user = SecurityUtils.getSubject(); UsernamePasswordToken token = new UsernamePasswordToken(phone, MD5Utils.getMD5Str(password).toCharArray()); //DigestUtils.md5Hex(password).toCharArray());// // token.setRememberMe(true); try { user.login(token); user.getSession().setTimeout(7*24*3600*1000); // 开发时设置永不过期,上线时需要调整 todo } catch (UnknownAccountException e) { logger.error("账号不存在:{}", e); return new ChariotResponseEntity<>(ChariotHttpStatus.USER_ACCOUNT_OR_PASSWORD_ERROR); } catch (DisabledAccountException e) { logger.error("账号未启用:{}", e); return new ChariotResponseEntity<>(ChariotHttpStatus.USER_NOT_ENABLED); } catch (IncorrectCredentialsException e) { logger.error("密码错误:{}", e); return new ChariotResponseEntity<>(ChariotHttpStatus.USER_ACCOUNT_OR_PASSWORD_ERROR); } catch (RuntimeException e) { logger.error("未知错误,请联系管理员:{}" + e.toString(), e); System.out.println(e.toString()); return new ChariotResponseEntity<>(ChariotHttpStatus.USER_OTHER_REASON); } SessionsSecurityManager securityManager = (SessionsSecurityManager) SecurityUtils.getSecurityManager(); DefaultSessionManager sessionManager = (DefaultSessionManager) securityManager.getSessionManager(); String sessionId = String.valueOf(user.getSession().getId());//这个就是A的sessionId
2.从redis根据条件获取sessionId,当然,因为之前并没有存入,所以获取不到,这里的条件是phone+“redist“,保证唯一String sessionId2 = jedisConfiguration.getJedisClient().get(phone+"redis");
3.判断sessionId2是否为空,如果为空的话,就走第4步,否则,就先根据sessionId2获取sessionKey,再根据sessionKey获取session,然后根据sessionManager删除指定session,也就是我们希望踢掉的用户的sessionif(StringUtil.isNotEmpty(sessionId2)) { SessionKey sessionKey = new WebSessionKey(jedisConfiguration.getJedisClient().get(phone+"redis"),request,response); try { Session session = securityManager.getSession(sessionKey); if(!sessionId.equals(sessionId2)) sessionManager.getSessionDAO().delete(session); }catch (Exception e){ e.printStackTrace(); } jedisConfiguration.getJedisClient().del(phone+"redis"); }
4.这步也就结束了,将新用户的sessionId存入redis,方便被下一个用户踢jedisConfiguration.getJedisClient().set(phone + "redis", sessionId);
这里是总代码,至于redis什么的,相信你们都会的。public ChariotResponseEntity login(String phone, String password,HttpServletRequest request,HttpServletResponse response) throws Exception { logger.info("POST请求登录"); if (StringUtils.isBlank(phone) || StringUtils.isBlank(password)) { return new ChariotResponseEntity<>(ChariotHttpStatus.USER_PARAMETER_ERROR); } Subject user = SecurityUtils.getSubject(); UsernamePasswordToken token = new UsernamePasswordToken(phone, MD5Utils.getMD5Str(password).toCharArray()); //DigestUtils.md5Hex(password).toCharArray());// token.setRememberMe(true); try { user.login(token); user.getSession().setTimeout(-1000L); // 开发时设置永不过期,上线时需要调整 todo } catch (UnknownAccountException e) { logger.error("账号不存在:{}", e); return new ChariotResponseEntity<>(ChariotHttpStatus.USER_ACCOUNT_OR_PASSWORD_ERROR); } catch (DisabledAccountException e) { logger.error("账号未启用:{}", e); return new ChariotResponseEntity<>(ChariotHttpStatus.USER_NOT_ENABLED); } catch (IncorrectCredentialsException e) { logger.error("密码错误:{}", e); return new ChariotResponseEntity<>(ChariotHttpStatus.USER_ACCOUNT_OR_PASSWORD_ERROR); } catch (RuntimeException e) { logger.error("未知错误,请联系管理员:{}" + e.toString(), e); System.out.println(e.toString()); return new ChariotResponseEntity<>(ChariotHttpStatus.USER_OTHER_REASON); } SessionsSecurityManager securityManager = (SessionsSecurityManager) SecurityUtils.getSecurityManager(); DefaultSessionManager sessionManager = (DefaultSessionManager) securityManager.getSessionManager(); String sessionId = String.valueOf(user.getSession().getId()); String sessionId2 = jedisConfiguration.getJedisClient().get(phone+"redis"); if(StringUtil.isNotEmpty(sessionId2)) { SessionKey sessionKey = new WebSessionKey(jedisConfiguration.getJedisClient().get(phone+"redis"),request,response); try { Session session = securityManager.getSession(sessionKey); if(!sessionId.equals(sessionId2)) sessionManager.getSessionDAO().delete(session); }catch (Exception e){ e.printStackTrace(); } Long result = jedisConfiguration.getJedisClient().del(phone+"redis"); } String result1 = jedisConfiguration.getJedisClient().set(phone + "redis", sessionId); UserVO retUser = userService.getUserById(getCurrentUserId()); return new ChariotResponseEntity<>(retUser, ChariotHttpStatus.OK); }
如果以上代码看着头痛,可以看我截取的部分SessionsSecurityManager securityManager = (SessionsSecurityManager) SecurityUtils.getSecurityManager(); DefaultSessionManager sessionManager = (DefaultSessionManager) securityManager.getSessionManager(); String sessionId = String.valueOf(user.getSession().getId()); String sessionId2 = jedisConfiguration.getJedisClient().get(phone+"redis"); if(StringUtil.isNotEmpty(sessionId2)) { SessionKey sessionKey = new WebSessionKey(jedisConfiguration.getJedisClient().get(phone+"redis"),request,response); try { Session session = securityManager.getSession(sessionKey); if(!sessionId.equals(sessionId2)) sessionManager.getSessionDAO().delete(session); }catch (Exception e){ e.printStackTrace(); } Long result = jedisConfiguration.getJedisClient().del(phone+"redis"); } String result1 = jedisConfiguration.getJedisClient().set(phone + "redis", sessionId);
个人感觉,我这样写的好处是准确的取到session,不用遍历,因为我在网上只看到过遍历出来取到的session,因为是自己的想法,所以,我认为自己是原创了,毕竟我也没找到其他人这么做的。
本文介绍如何在Shiro+SpringBoot框架中实现用户登录及踢出已登录用户的功能,通过Redis存储sessionId实现精确查找并删除特定用户会话。
813

被折叠的 条评论
为什么被折叠?



