限制在同一台电脑上只允许有一个用户登录

在这里插入图片描述

文章目录

            • 1. html 部分
            • 2. js部分
            • 3. 拦截器部分
            • 4. 认证授权部分
            • 5. 控制层部分
            • 6. 工具类

实现流程:
1.从reqest域中获取现在登陆的新sessionId
2.根据登陆的用户名从reqest域中获取已经登陆的老sessionId
3.判断老sessionId是否存在和新旧sessionId是否是否一致
如果一直返回当前用户和当前用户已经登陆的ip地址
前台根据返回的结果页面弹框提示

1. html 部分
 <form id="formId" class="layui-form" action="${ctxPath}/login" method="post"><!-- 用户名 --><div class="layui-form-item"><div class="layui-input-block"><img src="${ctxPath}/assets/common/img/user.png"><input id="username" type="text" name="username" id="username" requiredlay-verify="required" placeholder="输入用户名" autocomplete="off" class="layui-input"></div></div><!-- 密码 --><div class="layui-form-item"><div class="layui-input-block"><img src="${ctxPath}/assets/common/img/password.png"><input type="password" name="password" id="password" required lay-verify="required"placeholder="输入密码" autocomplete="off" class="layui-input"></div></div><!-- 记住密码 --><div class="layui-form-item"><label class="layui-form-label" lay-tips="7天内免登陆"style="width:60px !important;padding:9px 0;margin-right:20px">记住密码</label><div class="layui-input-block"><input class="radio" type="radio" name="remember" value="on" title="是"><input type="radio" name="remember" value="off" title="否" checked=""></div></div><!-- 登录按钮  --><div class="layui-form-item"><button lay-filter="login-submit" id="submit" class="layui-btn layui-btn-primary loginBtn"lay-submit>登录</button></div></form>
2. js部分
<script>layui.use(['layer', 'form'], function () {var $ = layui.jquery;var layer = layui.layer;var form = layui.form;$("#submit").click(function () {$.ajax({url: "/checkLogin",type: 'POST',dataType: 'json',data: {username: $("#username").val()},async: false,success: function (msg) {var ip = msg.data.ip;if (ip != '') {if (window.confirm("用户'" + $('#username').val() + "'已在" + ip + "登陆,是否在本电脑登陆?")) {falg = true;} else {falg = false;}}$('#formId').submit();}});return falg;});var errorMsg = "${tips!}";if (errorMsg) {layer.msg(errorMsg, {icon: 5, anim: 6});}});
</script>
3. 拦截器部分
package com.gblfy.controller;import cn.stylefeng.roses.core.reqres.response.ResponseData;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;/*** 登陆前校验** @author guobin* @date 2021-01-27*/
@Controller
public class CheckLogInController {private final static Logger logger = LoggerFactory.getLogger(CheckLogInController.class);@RequestMapping(value = "/checkLogin", method = RequestMethod.POST)@ResponseBodypublic ResponseData CheckLogin(HttpServletRequest request, HttpServletResponse httpServletResponse) {
//        Boolean flag = false;//true-已经登陆 false-未登陆或登陆session一样String ip = "";//返回空-未登录。非空-已登录Map<String, Object> mmap = new HashMap<>();try {//获取当前用户的sessionIdString sessionId = request.getSession().getId();//当前sessionidString username = request.getParameter("username").trim();//用户名String sessionIdOld = (String) request.getServletContext().getAttribute(username);//老sessionId//如果老sessionId不为null 且新老sessionId不一致,则当前账号已有人登陆mmap.put("ip",ip);if (null != sessionIdOld && !"".equals(sessionId) && !sessionId.equals(sessionIdOld)) {ip = (String) request.getServletContext().getAttribute(username + "IP");mmap.put("ip",ip);}} catch (Exception e) {logger.error("从session中获取用户登陆ip失败:", e);ip = "";}return ResponseData.success(mmap);}
}
4. 认证授权部分
/*** 不需要权限验证的资源表达式*/List<String> NONE_PERMISSION_RES = CollectionUtil.newLinkedList("/assets/**","/checkLogin","/login", "/global/sessionError", "/kaptcha", "/error", "/global/error");
5. 控制层部分
/*** 点击登录执行的动作** @author gblfy* @Date 2019/11/23 5:42 PM*/@RequestMapping(value = "/login", method = RequestMethod.POST)public String loginVali(HttpServletRequest request) {String sessionId = request.getSession().getId();String username = super.getPara("username").trim();String password = super.getPara("password").trim();//如果开启了记住我功能String remember = super.getPara("remember");Subject currentUser = ShiroKit.getSubject();UsernamePasswordToken token = new UsernamePasswordToken(username, password.toCharArray());//如果开启了记住我功能if ("on".equals(remember)) {token.setRememberMe(true);} else {token.setRememberMe(false);}//执行shiro登录操作currentUser.login(token);//登录成功,记录登录日志ShiroUser shiroUser = ShiroKit.getUserNotNull();super.getSession().setAttribute("shiroUser", shiroUser);super.getSession().setAttribute("username", shiroUser.getAccount());try {//获取老sessionIdString sessionIdOld = (String) request.getServletContext().getAttribute(username);if (null != sessionIdOld && !sessionId.equals(sessionIdOld)) {//注销老sessionHttpSession session = (HttpSession) request.getServletContext().getAttribute(sessionIdOld);session.invalidate();}//获取老sessionId} catch (Exception e) {e.printStackTrace();//非正常清空session}//重新赋值
request.getSession().getServletContext().setAttribute(username, sessionId);request.getSession().getServletContext().setAttribute(sessionId, request.getSession());request.getSession().getServletContext().setAttribute(username + "IP", Inet4AddresslUtils.getReqIp(request));LogManager.me().executeLog(LogTaskFactory.loginLog(shiroUser.getId(), getIp()));ShiroKit.getSession().setAttribute("sessionFlag", true);return REDIRECT + "/";}
6. 工具类
package com.gblfy.controller;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import javax.servlet.http.HttpServletRequest;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;public class Inet4AddresslUtils {private final static Logger logger = LoggerFactory.getLogger(Inet4AddresslUtils.class);/*** 获取请求主机的ip地址** @param request* @return*/public static String getReqIp(HttpServletRequest request) {String ip = request.getHeader("x-forwarded-for");if ((ip == null) || (ip.length() == 0) || ("unknown".equalsIgnoreCase(ip))) {ip = request.getHeader("Proxy-Client-IP");}if ((ip == null) || (ip.length() == 0) || ("unknown".equalsIgnoreCase(ip))) {ip = request.getHeader("WL-Proxy-Client-IP");}if ((ip == null) || (ip.length() == 0) || ("unknown".equalsIgnoreCase(ip))) {ip = request.getRemoteAddr();}return ip;}/*** 获取服务器本机的ip地址** @return*/public static String getInet4Address() {Enumeration<NetworkInterface> nis;String ip = null;try {nis = NetworkInterface.getNetworkInterfaces();for (; nis.hasMoreElements(); ) {NetworkInterface ni = nis.nextElement();Enumeration<InetAddress> ias = ni.getInetAddresses();for (; ias.hasMoreElements(); ) {InetAddress ia = ias.nextElement();if (ia instanceof Inet4Address && !ia.getHostAddress().equals("127.0.0.1")) {ip = ia.getHostAddress();}}}} catch (SocketException e) {logger.error("获取ip地址异常", e);}return ip;}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/518217.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

FM算法介绍

概述 FM (Factorization Machine) 算法可进行回归和二分类预测&#xff0c;它的特点是考虑了特征之间的相互作用&#xff0c;是一种非线性模型&#xff0c;目前FM算法是推荐领域被验证的效果较好的推荐方案之一&#xff0c;在诸多电商、广告、直播厂商的推荐领域有广泛应用。 …

最新!Vicor 270V-28V DCM5614以96%效率提供1300W功率

近日Vicor 宣布推出隔离式稳压 270V-28V DC-DC 转换器 DCM5614&#xff0c;其采用 5.6 x 1.4 0.3 英寸 VIA™ 封装&#xff0c;额定输出功率为 1300W。据了解DCM5614 重量仅 178g&#xff0c;提供无与伦比的功率密度可达451W/in3 &#xff0c;支持功率密度、重量和效率都至关重…

JavaScript-jQuery事件

参考文档&#xff1a; https://jquery.cuishifeng.cn/ 事件 鼠标事件&#xff0c;键盘事件&#xff0c;其他事件 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Title</title><script src&…

58 集团大规模 Storm 任务平滑迁移至 Flink 的秘密

Flink-Storm 是 Flink 官方提供的用于 Flink 兼容 Storm 程序 beta 工具&#xff0c;并且在 Release 1.8 之后去掉相关代码。本文主要讲述 58 实时计算平台如何优化 Flink-Storm 以及基于 Flink-Storm 实现真实场景下大规模 Storm 任务平滑迁移 Flink。 背景 58 实时计算平台…

前后端敏感数据加密方案及实现_01

文章目录一、组成部分1. html2. js3. 拦截器4. 认证授权5. 控制层6. 工具类一、组成部分 1. html <form id"formId" class"layui-form" action"${ctxPath}/login" method"post"><!-- 用户名 --><div class"layu…

离屏渲染在车载导航中的应用

导读 与手机导航不同&#xff0c;高德地图的车机版&#xff08;AMAP AUTO&#xff09;直接面对各大车厂和众多设备商。这些B端用户采用的硬件参数参差不齐&#xff0c;提出的业务需求涉及到渲染中诸多复杂技术的应用&#xff0c;这对渲染性能提出了极高的要求。 最初车机版沿…

打造大数据和AI能力底座 联通大数据深度参与“新基建”

年初至今&#xff0c;国家关于“新基建”的政策持续发布&#xff0c;引起社会各界广泛关注。目前来看&#xff0c;官方定义的新型基础设施主要包括信息基础设施、融合基础设施、创新基础设施三方面内容。疫情过后&#xff0c;新型基础设施建设将承担起经济复苏的使命&#xff0…

技术人如何通过了解业务,获取晋升机会?

伐薪是阿里巴巴高级技术专家&#xff0c;14年初入阿里时&#xff0c;没有过多地思考业务痛点和了解业务策略。后来&#xff0c;经历过晋升&#xff0c;当晋升评委&#xff0c;主动学习业务&#xff0c;最后&#xff0c;完成了从技术专家向综合性 TL 转变。这一路下来&#xff0…

adb-获取包名/界面名、获取app启动时间、卸载app、退出app、查看所有进程、查看所有包名

获取包名/界面名 Mac/Linux&#xff1a; adb shell dumpsys window windows | grep mFocusedApp adb shell dumpsys window windows | grep mCurrentFocus adb shell dumpsys window | grep mCurrentFocusWindows: adb shell dumpsys window windows | findstr mCurrentFoc…

记一次代码重构

单一职责 功能单一 功能单一是SRP最基本要求&#xff0c;也就是你一个类的功能职责要单一&#xff0c;这样内聚性才高。 比如&#xff0c;下面这个参数类&#xff0c;是用来查询网站Buyer信息的&#xff0c;按照SRP&#xff0c;里面就应该放置查询相关的Field就好了。 Data…

​如何成为一个更好的 React 开发者?

作者 | Siradji Awoual译者 | 苏本如&#xff0c;责编 | 屠敏头图 | CSDN 下载自东方 IC出品 | CSDN&#xff08;ID&#xff1a;CSDNnews&#xff09;大家好&#xff01;希望你们在疫情期间平平安安。今天&#xff0c;我想在这里谈谈不同的内容。我想分享一些React的开发技巧和…

前后端敏感数据加密方案及实现_02

文章目录1. 环境2. vue部分3. 控制层4. 工具类1. 环境 组件版本springboot2.4.0后端框架3.0.0前端框架vue-router4.0.0-0ant-design-vue2.0.0-rc.3vuex4.0.0-0 2. vue部分 <template><a-layout-header class"header"><div class"logo">…

蚂蚁金服 3 个项目进入 CNCF 云原生全景图 | 开源

2019 年 6 月 25 日&#xff0c;全球知名开源组织云原生计算基金会 CNCF 宣布&#xff0c;蚂蚁金服正式成为 CNCF 黄金会员&#xff0c;蚂蚁金服表示将持续加大对开源项目的支持&#xff0c;包括 Kubernetes&#xff0c;ServiceMesh&#xff0c;Serverless&#xff0c;安全容器…

Knative 初体验:CICD 极速入门

Knative 社区很早就在讨论用 Tekton 替换 Build 模块的事宜。Knative Build 官方已经正式说明不再建议使用 Knative Build 了。 如果你知道 Knative Build 是什么相信你理解起 Tekton 就是很容易的一件事了。 Knative Build 对自己的一句话概述是&#xff1a;A Kubernetes-na…

关于 Docker ,你必须了解的核心都在这里了!

来源 | fysuccess来源 | CSDN博客&#xff0c;责编 | Carol头图 | CSDN 下载自视觉中国Docker引擎Docker Engine是具有以下主要组件的客户端-服务器应用程序&#xff1a;服务器是一种长期运行的程序&#xff0c;称为守护程序进程&#xff08; dockerd命令&#xff09;。REST AP…

如何在视频里任意抠图?阿里工程师做到了!

阿里妹导读&#xff1a;现在的我们在手机上花费了越来越多的时间&#xff0c;其中&#xff0c;视频又格外地吸引我们的注意力。有很多好玩的视频&#xff0c;需要把前景物体从视频中分割出来&#xff0c;这需要花费创作者99%以上的时间。今天&#xff0c;阿里资深算法专家任海兵…

启动vue项目失败,报错Failed at the node-sass@4.14.1 postinstall script.

在启动vue项目的时候报错 报错信息如下&#xff1a;npm ERR! code ELIFECYCLE npm ERR! errno 1 npm ERR! node-sass4.14.1 postinstall: node scripts/build.js npm ERR! Exit status 1 npm ERR! npm ERR! Failed at the node-sass4.14.1 postinstall script. npm ERR! This i…

DLedger —基于 raft 协议的 commitlog 存储库

尊敬的阿里云用户&#xff1a; 您好&#xff01;为方便您试用开源 RocketMQ 客户端访问阿里云MQ&#xff0c;我们申请了专门的优惠券&#xff0c;优惠券可以直接抵扣金额。请填写下您公司账号信息&#xff0c;点击上图&#xff0c;了解更多哦。 一、DLedger引入目的 在 Rocke…

不服来战!青藤发起“雷火引擎”公测赛 百万赏金寻顶尖白帽

2020年春天&#xff0c;以5G、人工智能、云计算为代表的“新基建”蔚然成风&#xff0c;着眼国家数字经济体系建设&#xff0c;打造数字经济体系底座的“新基建”&#xff0c;无疑成为中国经济整体应对未来发展的核心方案。可以说&#xff0c;没有任何一个时期比现在更能够彰显…

UI2CODE系列文章|如何批量制造高质量样本

在 UI2CODE 项目中&#xff0c;我们大量使用了深度学习方法来做一些物体检测。而深度学习模型的训练&#xff0c;避免不了需要大量的样本&#xff0c;因此如何制造大量样本&#xff0c;来满足模型训练需要是我们必须要解决的一个问题。在这篇文章中&#xff0c;我们将介绍我们如…