首先,我们要说明一下,本技术点的开发背景是shiro与springMvc结合环境下的开发方式。
由于shiro把用户登录后的信息都存在了自己封装的session中,所以要实现单一地址登录,我们需要关注到shiro的 session操作。技术实现步骤如下:
一、在shiro的xml配置文件中
1、加入sessionManager配置
<!-- shiro结合Session会话管理器 --> <bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager"> <!-- session的失效时长,单位毫秒 1小时: 3600000, 站点设置以 6小时 为主:21600000 --> <!-- 设置全局会话超时时间,默认30分钟,即如果30分钟内没有访问会话将过期 1800000 --> <property name="globalSessionTimeout" value="1800000"/> <!-- 删除失效的session --> <property name="deleteInvalidSessions" value="true"/> <!-- 是否开启会话验证器,默认是开启的 --> <property name="sessionValidationSchedulerEnabled" value="true"/> </bean>
2、在安全管理器中注入session管理器
<!-- securityManager安全管理器 --> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <property name="realm" ref="customRealm" /> <!-- 注入缓存管理器 --> <property name="cacheManager" ref="cacheManager"/> <!-- 注入session管理器 --> <property name="sessionManager" ref="sessionManager" /> </bean>
Ps:以上操作针对没有将session管理器注入到安全管理器的同学。因为我们之后需要用到sessionManager,如果没有注入,在运行时会报‘’ServletContainerSessionManager cannot be cast to org.apache.shiro.web.session.mgt.DefaultWebSessionManager‘’错误;
二、在登录的controller中判断重复session,并把他们关闭
1、在controller中写入如下的方法,用于根据当前登录用户,筛选出已登录session中重复登录的信息集合
/** * * @param currentUser 当前登录用户的shiro认证信息 * @return 重复登录的用户Session(shiro格式) * Description: 遍历同一个账户的现有的session用户信息并将重复的登录缓存信息输出 * @author mylydg * @date */ private List<Session> getLoginedSession(Subject currentUser) { //获得当前登录用户的全部session Collection<Session> list = ((DefaultSessionManager) ((DefaultSecurityManager) SecurityUtils .getSecurityManager()).getSessionManager()).getSessionDAO() .getActiveSessions(); List<Session> loginedList = new ArrayList<Session>(); Sys_User loginUser = (Sys_User) currentUser.getPrincipal();//获得当前用户信息 for (Session session : list) { Subject s = new Subject.Builder().session(session).buildSubject(); if (s.isAuthenticated()) { Sys_User user = (Sys_User) s.getPrincipal(); if (user.getLogin_Name().equalsIgnoreCase(loginUser.getLogin_Name())) { if (!session.getId().equals( currentUser.getSession().getId())) { loginedList.add(session);//把除当前登录用户的其他的同名用户session信息加入集合 } } } } return loginedList; }
2、在认证登录方法中关闭重复认证的session
@RequestMapping("/login") public String login(String username,String password,Model model) { //获取shiro的控制类Subject Subject subject = SecurityUtils.getSubject(); //获取身份信息 Sys_User cacheUser =(Sys_User)subject.getPrincipal(); if(cacheUser!=null) { model.addAttribute("user", cacheUser); return "sys/user/main"; } if(username == null) { return "sys/user/login"; } //创建一个用于验证用户名和密码的token UsernamePasswordToken token = new UsernamePasswordToken(username, password); Sys_User user; try { //验证用户名密码 subject.login(token); //----------------------------关键代码 star-------------------------------------------- //检查当前登录用户信息,将存在重复登录用户信息筛选出来 List<Session> loginedList = getLoginedSession(subject); for (Session session : loginedList) { session.stop();//关闭重复用户登录信息缓存 } //----------------------------关键代码 end-------------------------------------------- //这个方法是获取shiro里面的登录信息,如果reaml里面传入的是对象,这里就是 //对象,如果是字符串,这里就是字符串,按照相应的格式转换使用即可 Object o = subject.getPrincipal(); user = (Sys_User)o; System.out.println(user.getLogin_Name()+" "+user.getPassword()); model.addAttribute("user", user); } catch (UnknownAccountException e) { model.addAttribute("errormessage", "用户名错误!"); System.out.println("userName 用户名错误!"); return "sys/user/login"; } catch (IncorrectCredentialsException e) { model.addAttribute("errormessage", "密码错误!"); System.out.println("passwd 密码错误"); return "sys/user/login"; }
再次运行系统后,功能实现~