在 Web 中获取 MAC 地址
两年前做的一个项目,当时客户的需求还没有完成,客户就提出了解决安全的问题,这是当时写的一个记录,分享到这里。
解决安全登录的问题
去给客户演示系统,演示完刚开发完的系统以后客户就将我们的系统批的遍体鳞伤,这时才知道自己的系统比想象中的更不堪(不是我等无能,是各种原因全都赶上了)。在如此不堪的系统面前,客户又提出了一个需求,要限制用户的登录机器。补充一下,演示的系统是一个 ERP 系统,是 BS 结构的,后端用 Java 写的,项目是部署在阿里云上的,客户的每个门店都可以访问。但是,客户要求,要限制能够登录系统的电脑,客户明确要求需要绑定 MAC 地址。因为系统里的数据比较重要,不能让员工回家登录系统,因此必须要进行限制。
解决思路
这样的问题,能想到的解决思路只有两个:(当时的思路,其实思路远不止这些)
1、在 EXE 文件中嵌入一个浏览器控件,浏览器控件中显示 ERP 的页面,EXE 获取 MAC 地址后提交到服务器。感觉这样先是要处理 EXE 提交的 MAC 地址,然后还要和页面交互,想想貌似比较复杂,就否掉了。
2、写一个 OCX,让页面中的 JS 与 OCX 进行交互,OCX 获取到 MAC 地址后,将 MAC 返回给 JS,JS 通过 DOM 操作写入到对应的表单中,然后和用户名、密码一起提交给服务器。感觉这个好像实现起来还比较简单。就这个吧!
OCX 中获取 MAC 地址的关键代码
OCX 中可以直接调用 Windows 操作系统的 API 函数,写起来也比较简单,代码如下:
BSTR CGetMacCtrl::GetMacAddress(void)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
CString strResult;
// TODO: 在此添加调度处理程序代码
ULONG outBufLen = sizeof(IP_ADAPTER_ADDRESSES);
PIP_ADAPTER_ADDRESSES pAddresses = (IP_ADAPTER_ADDRESSES*)malloc(outBufLen);
if (pAddresses == NULL)
{
return NULL;
}
if(GetAdaptersAddresses(AF_UNSPEC, 0, NULL, pAddresses, &outBufLen) == ERROR_BUFFER_OVERFLOW)
{
free(pAddresses);
pAddresses = (IP_ADAPTER_ADDRESSES*)malloc(outBufLen);
if (pAddresses == NULL)
{
return NULL;
}
}
wchar_t acMAC[32] = { 0 };
if(GetAdaptersAddresses(AF_UNSPEC, 0, NULL, pAddresses, &outBufLen) == NO_ERROR)
{
for(PIP_ADAPTER_ADDRESSES pCurrAddresses = pAddresses; pCurrAddresses != NULL; pCurrAddresses = pCurrAddresses->Next)
{
// 确保 MAC 地址的长度为 00-00-00-00-00-00
if(pCurrAddresses->PhysicalAddressLength != 6)
{
continue;
}
wsprintf((LPWSTR)acMAC, _T("%02X-%02X-%02X-%02X-%02X-%02X"),
int (pCurrAddresses->PhysicalAddress[0]),
int (pCurrAddresses->PhysicalAddress[1]),
int (pCurrAddresses->PhysicalAddress[2]),
int (pCurrAddresses->PhysicalAddress[3]),
int (pCurrAddresses->PhysicalAddress[4]),
int (pCurrAddresses->PhysicalAddress[5]));
break;
}
}
free(pAddresses);
strResult = acMAC;
return strResult.AllocSysString();
}
代码差不多就这样吧,我用的 VS2012 写的 ActiveX,编译生成 OCX。
在 Web 中进行测试
在 Web 中测试也比较简单,通过 clsid 引入 OCX 文件,然后 JS 调用 OCX 文件中的函数,函数返回 MAC 地址给 JS,JS 进行 DOM 操作,代码如下:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf8">
<title>获取Mac地址Demo</title>
</head>
<body>
<object id="getmac" classid="clsid:52931A6A-93B4-4750-8FE6-B666E90B1D54"
codebase="'getmac.ocx'" style="display:none"></object>
<h1>MAC:</h1>
<span id="mac"></span>
<input type="text" id="macAddress" name="macAddress" value="" />
</body>
<script>
var mac = getmac.GetMacAddress();
document.getElementById("mac").innerHTML = mac;
document.getElementById("macAddress").value = mac;
document.getElementById("macAddress").style.display = '';
</script>
</html>
通过 object 标签引入了 OCX 文件,定义了 id 为 getmac,然后通过 getmac 来调用 OCX 中的函数 GetMacAddress() 获取 MAC 地址。
经过简单的测试还是可以的,然后我整合进入了 JeeSite 系统中(后端是用 Java 的开源项目 JeeSite 写的),测试以后发现 ERP 的页面对 IE 浏览器支持不好。因为 OCX 只能在 IE 浏览器中使用,结果这个方案就放弃了。后来,找到一个开源的 Chrome 的插件,也完成 MAC 地址的获取,该 Chrome 插件分为两部分,一部分是 Chrome 的插件,另外一个是 EXE 文件,该 EXE 文件也是与插件进行通信的,由于这个 Chrome 插件不是我写的,我就不往这里放了。其实,Chrome 的插件也只支持 Chrome 浏览器,如果客户使用的是 FireFox 浏览器的话又会有兼容性的问题,因此事后还找到了其他的解决方法,其他的方案就不再依赖插件了,也就和浏览器无关了,也就不存在兼容性的问题了,不过想到那个解决方法时,那个项目其实已经凉了,至于解决的方法有机会再接着介绍吧。
- Rafy 领域实体框架示例(1) - 转换传统三层应用程序
- android view事件分发机制
- Rafy 领域实体框架演示(2) - 新功能展示
- ormlite介绍一
- 从Encoder到Decoder实现Seq2Seq模型(算法+代码)
- 【Java SE】Java NIO系列教程(六) Selector
- Rafy 领域实体框架演示(3) - 快速使用 C/S 架构部署
- Rafy 领域实体框架演示(4) - 使用本地文件型数据库 SQLCE 绿色部署
- spring 的OpenSessionInViewFilter简介
- Android TextView中文字通过SpannableString来设置超链接、颜色、字体等属性
- 【Java SE】Java NIO系列教程(三) Buffer
- android混淆
- 一步一步创建ASP.NET MVC5程序[Repository+Autofac+Automapper+SqlSugar](三)
- 两个activity或者activity和fragment传值
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 安装Ubuntu20.04与安装NVIDIA驱动的教程
- Ubuntu下安装nvidia显卡驱动(安装方式简单)
- Ubuntu 20.04 apt 更换国内源的实现方法
- Android设计模式之单例模式解析
- Android屏蔽软键盘并且显示光标的实例详解
- Android实现底部缓慢弹出菜单
- Ubuntu20的tzselect设置时间失效的问题,树莓派服务器(推荐)
- 安装Ubuntu 20.04后要做的事(小白教程)
- Ubuntu20.04安装Python3的虚拟环境教程详解
- Android编程实现播放视频时切换全屏并隐藏状态栏的方法
- Android UI设计与开发之仿人人网V5.9.2最新版引导界面
- PopupWindow使用方法详解
- Android 中cookie的处理详解
- Android UI设计与开发之ViewPager仿微信引导界面以及动画效果
- Android UI设计与开发之ViewPager介绍和简单实现引导界面