zoukankan      html  css  js  c++  java
  • 关于shiro安全框架实现同一用户同一时刻仅可在一个地址登录的技术实现

      首先,我们要说明一下,本技术点的开发背景是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";
             }

    再次运行系统后,功能实现~

  • 相关阅读:
    从程序员到项目经理(24):怎样给领导汇报工作
    从程序员到项目经理(22):对绩效考核的吐槽
    从程序员到项目经理(23):项目管理不能浑水摸鱼
    从程序员到项目经理(21):以德服人才能口服心服
    从程序员到项目经理(19):让员工为目标而干活
    从程序员到项目经理(20):谁都需要成就感
    从程序员到项目经理(18):想改变任何人都是徒劳的
    从程序员到项目经理(17):不要试图和下属做朋友
    从程序员到项目经理(16):你不是一个人在战斗--思维一换天地宽
    [SQL] 不合并重复数据 union all
  • 原文地址:https://www.cnblogs.com/mylydg/p/9604273.html
Copyright © 2011-2022 走看看