【学习笔记】如何实现同一设备下用户登录过无需再登录?

具体需求:想实现同一账号,同一时刻,同一设备,用户状态之间共享

同一账号,只能在一台设备登录

解决方案1:

关键点在于不同设备,因此需要有能够区别不同设备的指标–MAC地址
获取MAC地址可以通过cmd 命令行中,我们可以通过 nbtstat -a [IP]命令就可以根据IP地址获取到MAC地址。

nbtstat -a [IP] 基本原理:NBTSTAT 代表“NETBIOS Over TCP/IP Statistics” 运行在该计算机上的应用程序使用的 NetBIOS 名称列表,NetBIOS 的主要目的是允许不同计算机上的应用程序进行通信和建立会话以访问共享资源(如文件和打印机),并通过局域网 (LAN) 找到彼此,要确定给定NetBIOS名称的主机的IP地址,需要通过广播“name query”的数据包来进行查询,响应将会包含具有该名称的主机的IP地址。

try{
String str = "";
Process process= 
 Runtime.getRuntime().exec("nbtstat -A " + ipAddress);//
InputStreamReader reader = new InputStreamReader(process.getInputStream());
BufferedReader br = new BufferedReader(reader);

while((str = br.readLine()!=null))
{
	if(str.indexOf("MAC")>1)
{
	String macAddress= str.substring(str.indexOf("MAC")+9,str.length());
	macAddress = macAddress.trim();
	return macAddress;
}
}
	process.destroy();
	br.close();
	reader.close();
}
catch(IOException ex)
{
	throw new MyException("I/O error");
}

客户端的IP地址如何获得呢?
没有代理服务器的情况下:


public String getIpAddress(HttpServletRequest request) { 

 return request.getHeader("x-forwarded-for");
 }

有代理服务器的情况下,例如Nginx这些反向代理软件,所以无法获取到客户端真实的IP地址,因此,就没办法直接从转发请求获得IP地址,但是!我们依旧可以在转发请求的HTTP头信息中,通过获取X-FORWARDED-FOR信息来跟踪原来的客户端IP地址和原来客户端请求的服务器地址,(因为当访问服务器资源时,先由代理服务器去访问服务器的资源,代理服务器再将访问到的结果返回给浏览器**,因此通过上述方法得到的其实是代理服务器的地址**)

反向代理:中间商,将客户端的请求转发到后面的服务器,客户端并不知道原来我的请求已经被转发过了;
正向代理:比如客户端想访问内网服务器的资源,需要通过VPN来实现,客户端自主选择地通过被代理软件来转发请求

那到底如何得到呢?默认情况下,利用上述方法得到得是127.0.0.1;因此我们可以让Nginx在收到客户端直接请求时,将客户端IP保存起来,并在请求真正后台时将真实IP放到Header中,再取获取这个Header

server {
    listen       80;
    server_name  localhost;
    location / {
        proxy_set_header X-Real-IP $remote_addr;//取出客户请求过来的IP,一般放最后一次代理IP
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;//将所有代理IP拼接起来
        root   html;
        index  index.html;
    }
}

HTTP请求头2个字段:
REMOTE_ADDR:(发出请求的远程主机的IP地址,代表客户端的IP,是服务端根据客户端IP指定的,如果说用了代理的话,浏览器就会先访问这个代理服务器,这样就会将这个地址设为代理机器的IP);
x_forwarded_for:(HTTP请求端真实的IP,通过了HTTP代理或者负载均衡服务才会添加此项,代理服务器通常会增加一个叫做x_forwarded_for的头信息,把连接它的客户端IP(即真正的客户端)加到这个头信息里,这样就能保证服务端能获取到真实IP)

Java端获取IP

	public static String getClientIP(HttpServletRequest request)
	{
	String ip = request.getHeader("X-Real-IP");
 if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
        ip = request.getHeader("X-Forwarded-For");
    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
        ip = request.getHeader("Proxy-Client-IP");
        //Proxy-Client-IP/WL-Proxy-Client-IP :这个一般是经过apache http服务器的请求才会有,
        //用apache http做代理时一般会加上Proxy-Client-IP请求头,
    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
        ip = request.getHeader("WL-Proxy-Client-IP");
        //而WL-Proxy-Client-IP是weblogic插件加上的头。
    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
        ip = request.getRemoteAddr();

	}

通过IP地址得到MAC值之后,首次登录可以将该MAC值作为redis的键(最好还是先通过加密算法加密一下),以用户信息存入redis中(要记住设置过期时间,同时为了保证安全性,应当可以使用MD5加盐值的方式对该用户信息加密);不同的终端同时登录请求,会先走获取该设备MAC值的流程,再将该值去redis中查询,若存在一样的MAC的终端则可以登录进来,则直接将用户信息放入该请求的cookie中,进行之后域名间的共享

如果我想同一时间两个设备的用户过来,实现新登录的设备取代原来的设备,获取MAC值并查询到Redis中并不存在后,登录流程再取代原来的MAC值(然后通过模糊匹配的方式找到MAC值,删除这个键;或者不删除,该键的存活时间较短直接等过期删除)

(MAC值取决于设备的网络接口,一般来说MAC地址的设计都是永久且固定的
注意! 这种最好是要向客户询问意见,是否保留用户信息,这样才能保证用户信息安全。

参考:

  • https://www.jianshu.com/p/2b134607a3b9
  • https://www.cnblogs.com/wang1001/p/9605761.html
  • https://www.ncsc.gov.ie/emailsfrom/Shadowserver/DoS/NetBIOS/

解决方案2:

服务端将sessionid存储在本地,服务端再将sessionid保存在cookie中返回给客户端浏览器中,只要浏览器没关,之后的通信都会在header中携带cookie,但浏览器关了就没了,因此可以利用LocalStorage或SessionStorage来进行存储,它们都是讲数据保存在本地上,像LocalStorage 就保存在Users\Username\AppData\Local\Google\Chrome\UserData\Default\Local Storage,这样也实现了数据的持久化,这里可以通过前端的方式进行保存和读取

1.  `localStorage.key = value;`//存键
2.  `localStorage[key] = value;`//存键为key的值为value
3.  `localStorage.setItem(key, value);`//同时存储键值对
4.   `localStorage.getItem(key);`//获得键的值
5.  `localStorage.key(index);`//根据索引查找键

补充知识点

IP地址获取、通过域名得到IP地址、通过IP地址获取MAC地址:

参考《图解TCP/IP》:

  • 一个客户端要想与网络连接,就必须要有IP地址:
    通过DHCP动态配置向本地DHCP服务器来获得一个IP地址,请求期间是通过广播的方式向服务器发送UDP请求,DHCP服务器通过以CIDR块分配IP地址,返回DHCP ACK报文给客户端;交换机收到这个DHCP服务器发过来的相应报文;交换机是自学习的,因此可以知道是给哪个客户端;客户端收下了这个ACK得到IP地址和DNS服务器的地址,这样这个设备就拥有了一个IP地址就可以进行web页面的获取了~

  • 客户端发送请求时需要知道比如www.baidu.com 的IP地址
    从域名转换成IP地址都是通过DNS服务进行的

DNS作为应用层协议,将主机名转换为背后的IP地址,通过位于网络边缘的客户和服务器,实现关键的名字到地址转换功能
各级的DNS服务器包含对应等级的映射;注意!各级DNS服务器发送的请求和回答报文都是通过UDP数据报经过端口53发送的–《图解TCP/IP》

为什么采用UDP呢?有待补充

  • 但知道IP地址还不够,还需要知道MAC地址
    IP地址与MAC地址的区别?
    IP地址是网络层的,而MAC地址是在数据链路层,MAC地址是不会随着设备地址的变而变更,总是只有相同的MAC地址, 好比说,IP地址就是你现有地址,会随着你搬家而改变;MAC地址就是你老家地址,有时候IP地址找不到你的时候,找到你老家总能找到你

  • 为什么需要这两个地址,IP地址不够吗?
    IP地址就是当主机移动的时候,IP地址需要改变,因为会连接不同的网络;
    而MAC地址是用于局域网的,通过相同网络下的交换机交换数据到网络边界的路由器才能够转发到其他网络中,而如何到达哪个"其他网络"就是通过IP地址来确定的;
    如果只有IP地址,会导致每到一个主机,都需要将收到的每帧数据向上传输判断是不是IP地址匹配,这样就导致主机会被局域网上发送的每!一!个!帧! 中!断! 这当然不行因此有了MAC地址。

  • 在知道IP地址的情况下,如何知道MAC地址?
    ARP 协议(地址解析协议,只为同一个子网上的主机和路由器接口解析IP地址)
    每台主机或路由器都在内存中有一个ARP表,这个表包含IP地址到MAC地址的映射关系,(同时还包含了TTL过期事件(一般为20分钟))如果说这个ARP表找不到对应的NAC地址,此时就需要利用ARP协议来解析这个地址,以MAC广播地址(FF-FF-FF-FF-FF-FF)来发送这个分组,然后这个子网上所有的设备都能收到,收到这个ARP分组后,就会传给ARP模块,各自去查自己的IP地址是否和这个ARP分组的IP地址相同,相同则返回这个 IP地址-MAC地址映射 的ARP分组相应给对方,然后询问方再更新自己的ARP表

ARP查询和响应分组中一般包含 发送和接收IP地址及MAC地址,
但是查询分组是在广播帧发送的(当然,因为不知道MAC地址)
而相应地址是以标准帧发送的,(当然,是从目的地址发送出去的)
因此可以 看到这个ARP分组包含了MAC地址(链路层地址的字段)
也包含了IP地址( 网络层地址的字段)
因此可以把它看成是 跨越链路层和网络层边界的协议

无线LAN(WIFI)

802.11 无线LAN体系结构需要包含BSS、交换机或路由器、

BSS是什么?

BSS是基本服务集,(也可以看成是一个小型局域网)
一个BSS包含一个或多个无线站点和一个中央基站(负责协调与之相关联的多个无线主机的传输,802.11体系中又称之为接入点);家庭网络中,有一个基站和一台将该BSS连接到因特网中的路由器

设备如何与一个基站关联,从而建立通信呢?
每个中央基站都会周期性的发送信标帧,而这些帧又包含这个基站的SSID和MAC 地址,为了得知正在发哦是那个信标帧的基站,就需要扫描信道,找到可能是当前区域的基站发出的信标帧(因为可能会出现很多个基站,比如在商业街中,就能收到很多家店的信号很好的wifi连接,这就是wifi丛林);通过信标帧了解到可用的基站,设备再选择一个基站进行关联;之后再向基站发送一个关联请求指针,并且这个基站以一个关联响应帧进行响应,之后进行了关联,这个设备希望加入这个基站的子网,通过关联的基站向这个子网发送一个DHCP发送报文获取这个基站子网中的一个IP地址,这样就可以视这个设备为这个子网中的另一台主机

移动超出一个基站的覆盖范围而到达另一个基站的覆盖范围后,将会改变与之关联的基站,这就是切换。

相同的IP子网下一般会部署多个BSS,那无线站点之间如何维持进行中的TCP会话,无缝地从一个BSS移动到另一个BSS呢?

主机从BSS1移动到BSS2,如果连接两个BSS的互联设备不是一台路由器,则两个BSS的所有站点都属于同一个IP子网,所以可以保持自己的IP地址和所有正在进行的TCP连接,这样就可以不用重连也能扩大wifi信号的范围了;

但如果是一台路由器,就需要在移动进入的子网中获得一个新地址,这种地址变化就会打断进行中的TCP连接,这样用户这边需要重新登录网络或者感觉到了卡顿

说人话就是,比如我们在校园里,到了食堂会有校园网;到了宿舍也会收到校园网;随着我们向宿舍移动,接收到宿舍的校园WIFI的强度逐渐增强而食堂的WIFI强度逐渐减弱;
如果两个BSS之间互连设备不是一台路由器,就意味着没有路由器作为它们两个网络的中间桥梁,也就是说不需要中间桥梁,属于同一个网络下的;因此就可以解除与食堂wifi的关联,转而连接上宿舍wifi,同时还保持着我们手机的IP地址和TCP会话的连接!【具体怎么实现呢?】

但如果是通过路由器互连呢?路由器就是网络的边界,这就意味着你从食堂移动到宿舍的时候,其实是跨越了两个网络,那此时你的手机就需要重新获取IP地址,你的IP地址发生了改变,自然就无法再使用当前的TCP连接(确定TCP连接四元组:目标/源IP地址,目标/源端口,一个改变了就是新的TCP连接)因此就总需要重新登录;

那我如果不想被打断连接,该怎么办呢?
可以通过移动IP来解决这个问题。
【具体内容有待学习。。。】

相关疑问,wifi切换到数据如何保证无缝连接?
wifi切换到移动数据,一定会出现断连的状态
用无线网络,wifi路由器会分配一个IP地址,使用这个IP地址加入到庞大的互联网中进行通信
使用移动数据,移动网络也会分配一个IP地址,用这个地址进行通信;

现有做法:连上wifi后仍然保持蜂窝网络连接不变,这就是为啥会出现连上wifi后还走流量
还有一种方案是:类似于移动IP的方案,在网络中设置一个锚点,用户不管使用什么网络都和这个锚点建立隧道,对外通信使用这个锚点分配的IP
WiFi和移动数据之间切换为什么会一定断线? - 某火山的回答 - 知乎 https://www.zhihu.com/question/57935185/answer/155132015
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

54V

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值