Springboot + redis+shiro 限制 同一账号 同时 多处登录

5 篇文章 0 订阅
3 篇文章 0 订阅

从网上看了很多解决方案,用的最多的 应当是SessionId 了。方案虽多,适合自己的才是最好的。

之前做了一个 在线用户的统计 和 管理员 踢出激活在线用户的功能,因此我得到了一个启发。程序是死的,人是活得,我可不可以定一些规则,让程序 根据我的规定 来 运行。

思路:

1.定规则。

将 踢出的用户 画一个标识,也就是 访问的Sess ionId。踢出了 我将它标记为false

如果 SeeioId 标识为false 就强制退出用户

2.监听

定了规则之后我要监视它,如果它满足规则,要执行相应的操作

 流程:

1.在登录时 保存 登录的用户Id 和访问的SessionId 到redis 使用Hash表的方式

2.在登录时,取出 保存的用户信息Map

3.判断 Map 的Size 

4.大于1,说明是第二次登录,取出 Map中的信息

5.判断 如果 该次请求的SessionId 不等于Map中的SessionId 并且 该次请求的用户Id 等于Map 中的用户Id

6.满足上述条件,则是 同一账号多处登录。将Map 中的SessionId 标记为false (这里是标记前一位登录的用户) 存入redis 

7.将标记的SessionId保存到redis中 用键值对的方式,Key 随便取,比如("ks",sessionId)


8.自定义Filter 这里使用  HandlerInterceptorAdapter 因为 该 颗粒度更高,可以使用 注入。

9.获取 被踢出的SessionId 的值 ,利用 get("ks") 在redis中取出

10.判断 值为 false 并且 该次请求的SessionId 等于 踢出的SessionId

11.退出,跳转

//源码

定规则:

 //此方法在 登录时调用

 public void kickOutLogin(String sessionId, String userId) {

        Jedis jedis = null;

        try {

            jedis = jedisPool.getResource();

             //保存用户Id,访问的SessionID 
            jedis.hset("kickoutlogin", sessionId, userId);

            //保存请求的SessionId,标识为true
            jedis.hset("kickoutSessionId", sessionId, "true");

            //设置过期时间为30分钟
            jedis.expire("kickoutSessionId", 30 * 60);
            jedis.expire("kickoutlogin", 30 * 60);

            //取出保存在redis中的域和值
            Map<String, String> map = jedis.hgetAll("kickoutlogin");
            if (map.size() > MaxSize) {
                for (Map.Entry entry : map.entrySet()) {
                    //域 = sessionId
                    String jessionId = (String) entry.getKey();
                   //值 = 用户Id
                    String uid = (String) entry.getValue();
                   //获取请求的标识
                    String kickoutSessionId = jedis.hget("kickoutSessionId", jessionId);
                    if (!kickoutSessionId.equals("false")) {

                        // sessionId 不同,userId相同, 表示同一账号 多处登录
                        if (!sessionId.equals(jessionId) && userId.equals(uid)) {
                            //false 表示踢出
                            jedis.hset("kickoutSessionId", jessionId, "false");

                            //被踢出的用户SesionId保存到redis
                            jedis.set("Ks", jessionId);

                        }
                    }
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }

    }

监听:

package com.example.springboot.shiro.core.shiro.filter;


import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.util.WebUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

//使用 HandlerInterceptorAdapter  可以注入资源 

public class SessionControlInterceptor extends HandlerInterceptorAdapter {
    @Autowired
    private JedisPool jedisPool;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        Subject subject = SecurityUtils.getSubject();
        //如果没有登录
        if (!subject.isAuthenticated()) {
            return true;
        }
        Jedis jedis = null;
        String kickoutlogin = null;
        try {
              //获取请求的SessionId
            String sessionId = request.getSession().getId();
            jedis = jedisPool.getResource();
            //获取被踢出的SessionId
            String jessionId=jedis.get("Ks");
            if (sessionId != null) {
               //做判断 容易空指针
                if (null != jessionId) {
                    //获取这次请求SessionId 的标识
                    kickoutlogin = jedis.hget("kickoutSessionId", jessionId);
                }
            }

            if (kickoutlogin != null) {
                //标记为 false 并且 该 次请求的sessionId 和踢出的SessionId 相同
                if (kickoutlogin.equals("false") && sessionId.equals(jessionId)) {
                   //退出
                    subject.logout();
                  //重定向
                    WebUtils.issueRedirect(request, response, "kickoutLogin");
                }
            }

          
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
        return Boolean.TRUE;
    }

}

关于  HandlerInterceptorAdapter 的配置 可以去看一下 Springboot+Shiro+redis 踢出在线用户 

 

  • 4
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
### 回答1: Spring Boot是一种用于快速开发Java应用程序的框架,它提供了许多便捷的功能和特性,如自动配置、简化的部署等。MyBatis Plus是一个MyBatis的增强工具,可以更便捷地操作数据库。Shiro是一个强大的Java安全框架,可以提供身份认证、授权、会话管理等安全相关的功能。Redis是一个高性能的键值对存储系统,常用于缓存、分布式锁等场景。Template是Spring框架中用于渲染视图的模板引擎。 综上所述,Spring Boot与MyBatis Plus、ShiroRedis Template一起使用可以构建一个功能强大、高效、安全的应用程序。Spring Boot提供了便捷的开发环境和配置,使得整个项目的搭建和部署更加简单。MyBatis Plus提供了简洁的API,可以更方便地操作数据库,减少了开发人员的工作量。Shiro可以提供安全相关的功能,保护应用程序的数据和资源安全。Redis作为缓存可以提高应用程序的访问速度,使用分布式锁等功能可以保证数据一致性和并发控制。Template可以方便地渲染视图,使得前端页面开发更加简单。 总之,Spring Boot与MyBatis Plus、ShiroRedis Template的集成可以帮助开发人员快速构建功能完善、高效、安全的应用程序。它们各自的特性和功能相互配合,提供了一种快速开发的解决方案,为开发人员提供了更好的开发体验。 ### 回答2: Spring Boot是一个用于简化Spring应用程序开发的框架,它提供了自动配置和快速开发的特性。MyBatis Plus是基于MyBatis的增强工具,它简化了与数据库的交互,提供了很多便捷的方法和功能。Shiro是一个用于身份认证和授权的安全框架,它可以帮助我们实现用户身份认证、权限控制和会话管理的功能。Redis是一个开源的内存数据库,它提供了对数据的高速缓存和持久化存储的功能。Redis Template是Spring对Redis进行操作的一个封装工具,它提供了一系列的方法用于对Redis进行增删改查的操作。 使用Spring Boot可以简化项目的搭建和配置,通过自动配置可以省去很多繁琐的步骤。使用MyBatis Plus可以不用编写繁琐的SQL语句,只需定义实体类和Mapper接口即可完成数据库的操作。使用Shiro可以轻松实现用户的身份认证和权限控制,保障系统的安全性。使用Redis可以提高系统的性能,通过缓存机制减少数据库的访问次数。 结合起来使用,可以构建一个高效、安全和可靠的Web应用程序。Spring Boot提供了集成MyBatis Plus和Shiro的插件,可以方便地使用这两个框架。Redis Template可以与Spring Boot的缓存框架一起使用,实现高速缓存。通过这些技术的使用,我们可以快速开发出功能完善的Web应用,提高开发效率和系统性能。 ### 回答3: SpringBoot是Java中一个开源的应用程序框架,它可以简化开发过程,提供了许多开箱即用的功能和库,使得开发者能够更快速地构建应用程序。 MyBatisPlus是一个基于MyBatis的增强工具,它提供了更方便、更强大的操作数据库的功能,大大简化了数据库操作的代码。 Shiro是Java中一个功能强大且易于使用的安全框架,它提供了身份验证、授权、加密、会话管理等功能,可以帮助开发者实现应用程序的安全控制。 Redis是一个开源的内存数据库,它可以用作缓存、消息队列等,具有高性能、持久化、分布式等特点。 Template是Spring框架中的一个模板引擎,它支持HTML、XML、JSON等多种模板语言,用于将动态数据渲染到模板中,生成最终的静态页面或其他格式的文件。 综合以上技术,可以构建一个高效、安全、可靠的Web应用。使用SpringBoot可以简化项目的搭建和配置,MyBatisPlus可以方便地操作数据库,Shiro可以保护应用程序的安全,Redis可以提高系统的性能和可扩展性,Template可以方便地生成动态页面。 例如,我们可以使用SpringBoot搭建一个基于MyBatisPlus的后台管理系统,使用Shiro完成用户的身份验证和权限控制,使用Redis作为缓存存储用户的会话信息,使用Template将动态数据渲染到页面中。这样的系统具有良好的性能和安全性,提供了友好的用户界面和丰富的功能。 总之,SpringBoot、MyBatisPlus、ShiroRedis和Template等技术可以共同协作,帮助我们构建出高质量、高效率的应用程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值