近期有个需求,需要获取客户端Mac地址作为白名单验证的依据。使用.net,B/S架构。先百度找了一些获取mac地址的方法,

using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.IO;
using System.Net;
using System.Configuration;
using System.Web;
using System.Security.Cryptography;
using System.Data;
using System.Web.UI.WebControls;
using System.Management;
using System.Diagnostics;
using System.Net.NetworkInformation;
using System.Runtime.InteropServices; namespace Qianxun.Common
{
public class MacAddress
{
#region 获取mac地址的一些方法
#region 1 通过IPConfig命令读取MAC地址(选用)
/// <summary>
/// 根据截取ipconfig /all命令的输出流获取网卡Mac
/// </summary>
/// <returns></returns>
public static List<string> GetMacByIPConfig()
{
List<string> macs = new List<string>();
try
{
ProcessStartInfo startInfo = new ProcessStartInfo("ipconfig", "/all");
startInfo.UseShellExecute = false;
startInfo.RedirectStandardInput = true;
startInfo.RedirectStandardOutput = true;
startInfo.RedirectStandardError = true;
startInfo.CreateNoWindow = true;
Process p = Process.Start(startInfo);
// 截取输出流
StreamReader reader = p.StandardOutput;
string line = reader.ReadLine(); while (!reader.EndOfStream)
{
if (!string.IsNullOrEmpty(line))
{
line = line.Trim(); if (line.StartsWith("Physical Address") || line.StartsWith("物理地址"))
{
macs.Add(line.Substring(line.IndexOf(":") + 1, line.Length - line.IndexOf(":") - 1));
break;
}
} line = reader.ReadLine();
} // 等待程序执行完退出进程
p.WaitForExit();
p.Close();
reader.Close();
}
catch (Exception ex) { }
return macs;
}
#endregion #region 2 通过WMI读取MAC地址
/// <summary>
/// 通过WMI读取系统信息里的网卡MAC
/// 该方法依赖WMI的系统服务,该服务一般不会被关闭;但如果系统服务缺失或者出现问题,该方法无法取得MAC地址。
/// </summary>
/// <returns></returns>
public static List<string> GetMacByWMI()
{
List<string> macs = new List<string>();
try
{
string mac = "";
ManagementClass mc = new ManagementClass(" Win32_NetworkAdapterConfiguration ");
ManagementObjectCollection moc = mc.GetInstances();
foreach (ManagementObject mo in moc)
{
if ((bool)mo[" IPEnabled "])
{
mac = mo[" MacAddress "].ToString();
macs.Add(mac);
}
}
moc = null;
mc = null;
}
catch(Exception ex)
{
} return macs;
}
#endregion #region 3 通过NetworkInterface读取MAC地址:1)如果当前的网卡是禁用状态(硬件处于硬关闭状态),取不到该网卡的MAC地址,(您可以通过禁用网卡进行试验)。2)如果当前启用了多个网卡,最先返回的地址是最近启用的网络连接的信息
// 返回描述本地计算机上的网络接口的对象(网络接口也称为网络适配器)。
public static NetworkInterface[] NetCardInfo()
{
return NetworkInterface.GetAllNetworkInterfaces();
} /// <summary>
/// 通过NetworkInterface读取网卡Mac
/// </summary>
/// <returns></returns>
public static List<string> GetMacByNetworkInterface()
{
List<string> macs = new List<string>();
try
{
NetworkInterface[] interfaces = NetworkInterface.GetAllNetworkInterfaces();
foreach (NetworkInterface ni in interfaces)
{
macs.Add(ni.GetPhysicalAddress().ToString());
}
}
catch (Exception ex)
{ }
return macs;
}
#endregion
#region 4 通过SendARP读取MAC地址
/// <summary>
/// 通过SendARP获取网卡Mac
/// 网络被禁用或未接入网络(如没插网线)时此方法失灵
/// </summary>
/// <param name="remoteIP"></param>
/// <returns></returns>
public static string GetMacBySendARP(string remoteIP)
{
StringBuilder macAddress = new StringBuilder(); try
{
Int32 remote = inet_addr(remoteIP); Int64 macInfo = new Int64();
Int32 length = 6;
SendARP(remote, 0, ref macInfo, ref length); string temp = Convert.ToString(macInfo, 16).PadLeft(12, '0').ToUpper(); int x = 12;
for (int i = 0; i < 6; i++)
{
if (i == 5)
{
macAddress.Append(temp.Substring(x - 2, 2));
}
else
{
macAddress.Append(temp.Substring(x - 2, 2) + " - ");
}
x -= 2;
} return macAddress.ToString();
}
catch
{
return macAddress.ToString();
}
} [DllImport(" Iphlpapi.dll ")]
private static extern int SendARP(Int32 dest, Int32 host, ref Int64 mac, ref Int32 length);
[DllImport(" Ws2_32.dll ")]
private static extern Int32 inet_addr(string ip);
#endregion #region 5 从注册表读取MAC地址
//常规用户可通过读取注册表项Windows Genuine Advantage获取到物理网卡地址。
//1)如果注册表项被修改,则无法取得该MAC地址
//HKEY_LOCAL_MACHINE\Software\Microsoft\Windows Genuine Advantage
#endregion
#endregion
}
}

测试时猛然发现多个客户端获取到的mac地址都是一样的,惊觉获取的是服务端的Mac地址,服务端语言获取服务端Mac,那么我需要获取客户端Mac,应该使用客户端语言,最先想到的是js(因为有碰到过客户端ip和服务端ip的问题,这里倒也能想清楚)。百度了一圈,mac地址需要ActiveX脚本支持,

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>ie浏览器获取客户端Mac地址</title>
</head> <body> <object classid="CLSID:76A64158-CB41-11D1-8B02-00600806D9B6" id="locator" style="display: none; visibility: hidden"></object>
<object classid="CLSID:75718C9A-F029-11d1-A1AC-00C04FB6C223" id="foo" style="display: none; visibility: hidden"></object>
<form name="myForm">
<br />
MAC地址:<input type="text" name="macAddress">
</form>
</body>
</html> <script language="javascript">
var sMacAddr = "";
var sIPAddr = "";
var sDNSName = "";
var service = locator.ConnectServer();
service.Security_.ImpersonationLevel = 3;
service.InstancesOfAsync(foo, 'Win32_NetworkAdapterConfiguration');
</script>
<script for="foo" event="OnObjectReady(objObject,objAsyncContext)" language="JScript">
if (objObject.IPEnabled != null && objObject.IPEnabled != "undefined" && objObject.IPEnabled == true) {
if (objObject.IPEnabled && objObject.IPAddress(0) != null && objObject.IPAddress(0) != "undefined")
sIPAddr = objObject.IPAddress(0);
if (objObject.MACAddress != null && objObject.MACAddress != "undefined")
sMacAddr = objObject.MACAddress;
if (objObject.DNSHostName != null && objObject.DNSHostName != "undefined")
sDNSName = objObject.DNSHostName;
}
</script> <script for="foo" event="OnCompleted(hResult,pErrorObject, pAsyncContext)" language="JScript">
myForm.macAddress.value = sMacAddr;
</script> <script>
//判断浏览器是否支持ActiveX控件
//if (window.ActiveXObject) {
//支持-通过ActiveXObject的一个新实例来创建XMLHttpRequest对象
var WshShell = new ActiveXObject("WScript.Shell");
//}
//else {
// $("#tips").html("请使用ie并将本系统域名加入受信任的站点,并在internet选项-受信任的站点中开启ActiveX插件和脚本的相关权限");
//}
</script>

而这个东西仅支持ie,但是客户系统对ie兼容性不好,如果要调整,工作量巨大,那么就只能让其他浏览器比如chorme去兼容ActiveX。

1.首先找到chorme for ActiveX扩展插件,试了好几个版本,也依然无法获取到mac地址,不知道是我的使用方式有问题,还是这个方法已经失效。(chorme已经升级到当前最新版本 96.0.4664.45(正式版本) (64 位))。

2.之后找到IE Tab扩展插件,但是好像仅仅是在chorme上嵌入了一个ie内核,这样系统同样是不兼容的。

3.然后找到了油猴,想着写一个脚本获取mac地址存入c盘的一个txt文本,然后系统去读取这个txt文件即可。奈何油猴写了个alert(‘hello world‘)也没生效,不知道是使用方法有误,还是相关机制阻止了这种毫无意义的打扰。想到另一个问题,如果是后端去保存文件,其实是保存到服务器,而后端读取文件也需要客户端进行上传。而客户端脚本是没有权限去操作文件直接保存到txt(有点木马的特性,奈何没有涉及到这一块的技术)。所以该方案暂时搁置。

4.又找到一个插件PluginOK,但是是付费插件,原理应该是js调用c++去获取计算机物理信息,然后通过双向通信集成到系统。感觉有些大材小用,也没有这么多预算,暂时搁置,也没实测。这一痛点,成就了一家企业。

提取问题的根本矛盾点:mac地址仅支持ie获取,系统不兼容ie,那么就只能分成两步,1.ie获取mac 2.使用chorme登录系统操作,这1和2之间需要产生一个联系来把1获取的数据传递给2,想到上次微信扫码登录的逻辑,使用了预登陆机制,联想到暴雪的安全令机制,有了些许思路:

1.login页面创建一条预登陆记录存入数据库,且获取到id,在页面上拼接成安全令登录url

2.用户使用ie登录前一步拼接而成的url获取到mac地址且根据入参id存入到对应的数据库记录中(用户的ie需要先进行配置:1.ie浏览器internet选项-安全-受信任的站点将系统域名加入受信任的站点 2.还是刚才的地方 自定义级别 将ActiveX控件和插件相关权限打开)

3.返回原来的login页面输入账号密码即可登录,正常逻辑登录之后,配合预登陆id(可以从数据库获取mac地址)可以进行mac地址白名单的匹配

曲线救国,安全令增加一些交互效果,各处增加操作详细说明,倒也算勉强完成了需求

获取客户端Mac地址的更多相关文章

  1. js获取客户端MAC地址

    最近遇到一个需求,医院要求呼叫中心账号必须对应MAC地址,也就是说该MAC地址必须和呼叫中心账号对应才可使用,这可就难道我了,这需求就要求每次都判断用户登录的电脑MAC地址是否有呼叫中心账号,当然只针 ...

  2. js 获取客户端mac地址

    js 获取客户端mac地址 javascript获取客户端网卡MAC地址和IP地址和计算机名 nodesj如何获得客户端的mac地址呢? 浏览器获取MAC地址 不限浏览器的mac地址取得的几种办法 I ...

  3. java 通过ip获取客户端mac地址

    java 通过ip获取客户端mac地址 package com.asppro.util; import java.io.BufferedReader; import java.io.IOExcepti ...

  4. 如何获取客户端MAC地址(三个方法)

    方法一: 调用Windows的DOS命令,从输出结果中读取MAC地址: public static String getMACAddress() { String address = "&q ...

  5. php/js获取客户端mac地址的实现代码

    这篇文章主要介绍了如何在php与js中分别获取客户度mac地址的方法,需要的朋友可以参考下   废话不多讲,直接上代码吧! 复制代码 代码如下: <?php   class MacAddr {  ...

  6. http协议本身能获取客户端Mac地址问题

    http 位于网络应用程 应用层 会话层 表示层 传输层 网络层 数据链路层 物理层 数据在最高层开始传输 没经历下面一层加一层的头,然后传入目的电脑再进行一层层的解刨,所以http本来没有mac而接 ...

  7. web网站获取客户端mac地址

    <HTML><HEAD><TITLE>WMI Scripting HTML</TITLE> <META http-equiv=Content-Ty ...

  8. 关于获取客户端Mac地址

    private static string GetClientMAC() { string mac_dest = string.Empty; try { string strClientIP = Ht ...

  9. php获取客户端mac地址

    exec('/sbin/arp -a 2>&1', $array, $return_val);dump($array);$mac = '';foreach($array as $valu ...

随机推荐

  1. postman如何解决下个接口依赖上一个接口数据

    解决思路:将上一个接口返回的数据保存起来,然后提供下个接口使用,postman中通过设置全局变量来保存数据 步骤1:在Tests中添加如下图js代码. var jsondata = JSON.pars ...

  2. DFS与BFS题解:[kaungbin]带你飞 简单搜索 解题报告

    DFS and  BFS 在解题前我们还是大致讲一下dfs与bfs的.(我感觉我不会bfs) 1.DFS dfs(深度优先算法) 正如其名,dfs是相当的深度,不走到最深处绝不回头的那种. 深度优先搜 ...

  3. .NET下使用ufun函数取CAM操作的进给速度

    UF_PARAM_ask_subobj_ptr_value,这个函数在封装的时候,给了很大一个坑啊. NXOpen.UF.UFParam.AskSubobjPtrValue(ByVal param_t ...

  4. docker内服务访问宿主机服务

    目录 1. 场景 2. 解决 4. 参考 1. 场景 使用windows, wsl2 进行日常开发测试工作. 但是wsl2经常会遇到网络问题.比如今天在测试一个项目,核心功能是将postgres 的数 ...

  5. 2.2 DDD Layers & Clean Architecture DDD分层和简洁架构

    DDD Layers & Clean Architecture DDD分层和简洁架构 There are four fundamental layers of a Domain Driven ...

  6. JVM:类加载与字节码技术-2

    JVM:类加载与字节码技术-2 说明:这是看了 bilibili 上 黑马程序员 的课程 JVM完整教程 后做的笔记 内容 这部分内容在上一篇笔记中: 类文件结构 字节码指令 编译期处理 类加载阶段 ...

  7. Alpha阶段发布声明

    发布声明 Alpha 1.Alpha版本功能说明 功能列表和详情图 模块 功能 展示 首页 查看首页博文,搜索博文,可供未登录用户使用 动态 查看推荐动态给未登录用户使用,登录用户可以查看关注动态.我 ...

  8. Spring Security 多过滤链的使用

    Spring Security 多过滤链的使用 一.背景 二.需求 1.给客户端使用的api 2.给网站使用的api 三.实现方案 方案一: 方案二 四.实现 1.app 端 Spring Secur ...

  9. 绘制PCB电路原理图的8种方法

    1.选择集成电路,变压器,晶体管等组件,这些组件体积庞大,有许多引脚并在电路中起主要作用,然后从选定的参考引脚中抽取,以减少错误. 2.如果PCB上标有元件编号(如VD870,R330,C466等), ...

  10. 用python检查矩阵的计算

    鉴于最近复习线性代数计算量较大,且1800答案常常忽略一些逆阵.行列式的计算答案,故用Python写出矩阵的简单计算程序,便于检查出错的步骤. 1.行列式 可自行更改阶数 from numpy imp ...