最近在做电子政务,给某局以及直属单位做统一的用户登录功能。登录界面有多级选择列表,如:局单位-->局业务处室-->局用户-->用户名,每次登录都得这么选择,繁琐的操作对那些机关领导来说确实是一件不容易的事,为此就希望把用户选择的信息,初始化一次,以后登录就不用再选择那么多了。于是就想到记录客户端的MAC地址来做为机器标识。但要在客户端能快速准确的获取到MAC地址还是一件不太容易的事。主要常见的方式有以下几种:
方法一:Javascript结合系统的ActiveX
优点:无需开发额外的代码,轻量级的实现。不需要服务器端进行处理,有客户端自行获取,传递到服务器端,速度比在服务器端获取好。
缺点:受客服端平台的限制,如安全级别设置较高,则无常正常执行。还有情况就是可靠性不是怎么好,有获取不到的情况。
其实最关键的还是用到两个ActiveX:
<OBJECT id=locator classid=CLSID:76A64158-CB41-11D1-8B02-00600806D9B6 VIEWASTEXT></OBJECT>
<OBJECT id=foo classid=CLSID:75718C9A-F029-11d1-A1AC-00C04FB6C223></OBJECT>
两个ActiveX都是系统自带,不用去下载或注册。
- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
- <html>
- <head><title>WMI Scripting HTML</title>
- <META http-equiv="Content-Type" content="text/html; charset=gb2312">
- <script language="JScript" event="OnCompleted(hResult,pErrorObject, pAsyncContext)" for=foo>
- document.forms[0].txtMACAddr.value=unescape(MACAddr);
- document.forms[0].txtIPAddr.value=unescape(IPAddr);
- document.forms[0].txtDNSName.value=unescape(sDNSName);
- //document.formbar.submit();
- </script>
- <script language="JScript" event=OnObjectReady(objObject,objAsyncContext) for=foo>
- if(objObject.IPEnabled != null && objObject.IPEnabled != "undefined" && objObject.IPEnabled == true)
- {
- if(objObject.MACAddress != null && objObject.MACAddress != "undefined")
- MACAddr = objObject.MACAddress;
- if(objObject.IPEnabled && objObject.IPAddress(0) != null && objObject.IPAddress(0) != "undefined")
- IPAddr = objObject.IPAddress(0);
- if(objObject.DNSHostName != null && objObject.DNSHostName != "undefined")
- sDNSName = objObject.DNSHostName;
- }
- </script>
- <META content="MSHTML 6.00.2800.1106" name=GENERATOR>
- </head>
- <body>
- <object id=locator classid=CLSID:76A64158-CB41-11D1-8B02-00600806D9B6 VIEWASTEXT></object>
- <object id=foo classid=CLSID:75718C9A-F029-11d1-A1AC-00C04FB6C223></object>
- <script language="JScript">
- var service = locator.ConnectServer();
- var MACAddr ;
- var IPAddr ;
- var DomainAddr;
- var sDNSName;
- service.Security_.ImpersonationLevel=3;
- service.InstancesOfAsync(foo, 'Win32_NetworkAdapterConfiguration');
- </script>
- <form runat="server" id="formfoo" name="formbar" method="post">
- <input name="txtMACAddr"/>
- <input name="txtIPAddr"/>
- <input name="txtDNSName"/>
- <asp:Button ID="Button1" runat="server" Text="Button" onclick="Button1_Click" />
- </form>
- </body>
- </html>
方法二:调用Win32API(推荐)
优点:成功率较高,不受客户浏览器的限制。
缺点:只能是Windows系统
- [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);
- private string GetClientIP()
- {
- string result = HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
- if (null == result || result == String.Empty)
- {
- result = HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"];
- }
- if (null == result || result == String.Empty)
- {
- result = HttpContext.Current.Request.UserHostAddress;
- }
- return result;
- }
- /// <summary>
- /// 获取Mac地址信息
- /// </summary>
- /// <param name="IP"></param>
- /// <returns></returns>
- public static string GetCustomerMac(string IP)
- {
- Int32 ldest = inet_addr(IP);
- Int64 macinfo = new Int64();
- Int32 len = 6;
- int res = SendARP(ldest, 0, ref macinfo, ref len);
- string mac_src = macinfo.ToString("X");
- while (mac_src.Length < 12)
- {
- mac_src = mac_src.Insert(0, "0");
- }
- string mac_dest = "";
- for (int i = 0; i < 11; i++)
- {
- if (0 == (i % 2))
- {
- if (i == 10)
- {
- mac_dest = mac_dest.Insert(0, mac_src.Substring(i, 2));
- }
- else
- {
- mac_dest = "-" + mac_dest.Insert(0, mac_src.Substring(i, 2));
- }
- }
- }
- return mac_dest;
- }
方法三:后台进程调用nbtstat命令
优点:无需额外开发组件,不受客户端平台的限制
缺点:受网络范围的限制,成功率较低,速度慢。
具体实现原理:通过nbtstat -a IP 命令将对方计算机的信息输出管道,然后捕获管道输出的内容,再通过正则表达式将MAC筛选出来。
- public static string GetCustomerMac(string IP)
- {
- string dirResults = "";
- ProcessStartInfo psi = new ProcessStartInfo();
- Process proc = new Process();
- psi.FileName = "nbtstat";
- psi.RedirectStandardInput = false;
- psi.RedirectStandardOutput = true;
- psi.Arguments = "-A " + IP;
- psi.UseShellExecute = false;
- proc = Process.Start(psi);
- dirResults = proc.StandardOutput.ReadToEnd();
- proc.WaitForExit();
- dirResults = dirResults.Replace("\r", "").Replace("\n", "").Replace("\t", "");
- Regex reg = new Regex("([0-9A-Fa-f]{2})(-[0-9A-Fa-f]{2}){5}", RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.Multiline | RegexOptions.RightToLeft);
- Match mc = reg.Match(dirResults);
- if (mc.Success)
- {
- try
- {
- return mc.Groups[0].Value.ToString();
- }
- catch
- {
- return "";
- }
- }
- else
- {
- reg = new Regex("Host not found", RegexOptions.IgnoreCase | RegexOptions.Compiled);
- mc = reg.Match(dirResults);
- if (mc.Success)
- {
- return "Host not found!";
- }
- else
- {
- return "";
- }
- }
- }