springboot利用session实现单点登录

我用的是servletcontext简单易操作,而且整个服务器端可以共享数据,服务器启动自动生成,关闭即销毁。刚好符合需求。

项目结构

直接开始代码;

 config里是不同类获取session的方法

获取request对象  GetRequest类

public class GetRequest {
    public static HttpServletRequest getRequest() {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        return request;
    }
}

已经得到request对象了,那得到其他的bean就很简单了。

获取session  GetSession类

public class GetSession {
    public static HttpSession getSession(){
        HttpServletRequest request = GetRequest.getRequest();
        HttpSession session = request.getSession();
        return session;
    }
}

获得servletcontext了,这个要是方法不对会报空指针异常,这个问题要重视 GetServletContext类

public class GetServletContext {
    public static ServletContext getServletContext()  {
        ServletContext servletContext = GetSession.getSession().getServletContext();
        return servletContext;
    }
}

config里还有两个类分别是检查session的方法CheckSession,和移除session的方法DelSecondUser

CheckSession类

检查session的方法,判断当前session中是否有用户登录信息,没有的话说明没登录,返回true,如果存在登录信息,取出当前sessionId以及servletcontext中此用户id对应的sessionId,判断两个sessionId是否相等,相等的话,说明是同一个连接会话,也返回true。不相等的话,就说明后面登录的sessionId已经覆盖掉了之前servletcontext中的sessionId,存在异地登录,返回false。

public class CheckSession {
    public static boolean checkSession() {
        HttpSession session = GetSession.getSession();
        User userInfo = (User) session.getAttribute("loginUser");
        if (userInfo == null) {
            return true;
        } else {
            ServletContext servletContext = GetServletContext.getServletContext();
            String sessionId = session.getId();
            String userId = String.valueOf(userInfo.getId());
            String oldSessionId = (String) servletContext.getAttribute(userId);
            System.out.println("old---------------"+oldSessionId);
            System.out.println("old---------------"+sessionId);
            /*如果不存在此用户的sessionId(一般不可能)                          或者新旧id相等,说明是同一个登录*/
            if (oldSessionId == null || oldSessionId.equals(sessionId)) {
                return true;
            } else {
                /*否则就是不同客户端登录,返回false*/
                return false;
            }
        }
    }
}

DelSecondUser类

移除session的方法,我这里每个页面拦截判断后都需要执行。

public class DelSecondUser {
    public static void delSecondUser(){
        HttpSession session = GetRequest.getRequest().getSession();
        session.removeAttribute("loginUser");
        /*存储一个状态,用于前端判断是多客户端登录,账号被挤掉了*/
        session.setAttribute("loginState","1");
    }
}

再看登录后

登录成功时,将用户信息存入session中,取出sessionId和用户Id,以用户id为key(因为每个用户id都是唯一的,sessionId会改变的)。

User userInfo = userService.findByAccountAndPassword(name, password);
        /*登录成功把用户信息存入session中,便于调用*/
        session.setAttribute("loginUser", userInfo);
        /*获取当前用户id并初始化为String类型*/
        String userId = String.valueOf(userInfo.getId());
        /*获取当前会话的sessionId*/
        String sessionId = session.getId();
        ServletContext servletContext = GetServletContext.getServletContext();
        /*以用户id为key,sessionId为value存储到容器中*/
        servletContext.setAttribute(userId, sessionId);
        session.removeAttribute("loginState");
        return "successful";

之后去拦截器那里进行判断:

这里我用的是登录成功后的应该界面的跳转,来测试功能有没有实现,如果实现的话,我们在例外一个浏览器登录是就会把最开始登录的那个浏览器挤掉,进行操作的话就需要从新登录

@RequestMapping({"/index", ""})
    public String index(ModelMap modelMap) {
        if (!CheckSession.checkSession()) {
            DelSecondUser.delSecondUser();
            return "login";
        } else {
            return "popup";
        }
    }

至于怎么在登录页判断是不是被挤掉账号而过来的进行提示

记得我们在移除session的那个方法里写了这样一个语句。

 session.setAttribute("loginState","1");
/*存储一个状态,用于前端判断是多客户端登录,账号被挤掉了*/

如果是被挤到的,那么给前端一个1的状态。

然后在登录页放一个隐藏的标签来接收它:

<span style="display:none;"th:if="${session.loginState!=null}"th:text="${session.loginState}" id="ifLogin"></span><!--如果是1代表是被挤掉而重定向过来的-->
<span style="display: none;" th:if="${session.loginState==null}" th:text="0" id="ifLogin"></span><!--默认是0-->

在登录页的js里写一个判断方法:

//判断是不是被挤出登录
function ifLogin(){
    var state = $('#ifLogin').text().trim();
    if (state == "1"){
        layer.confirm('您的账号在其他地方登录,请确认是否本人操作?', {
            btn: ['是我本人操作','不是我,立即修改密码'] //按钮
            ,closeBtn:0
            ,title:"警告"
            ,btnAlign: 'c'
        }, function(){
            layer.msg('好的!请注意保护个人账号安全!',{icon:6});
        }, function(){
            location.href="forgetPd";
        });
    }
}

每次进入页面都进行判断,是不是1,是1就给出提示。

如果在登录界面再次登录,那么就移除掉这loginstate状态,前面登录那里有写到。

最后就完成了,这个登录

问题可能会出现在ServletContext的获取上,可以去查查怎么获取这个值

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值