【问题标题】:How to get a unique computer identifier in Java (like disk ID or motherboard ID)?如何在 Java 中获取唯一的计算机标识符(如磁盘 ID 或主板 ID)?
【发布时间】:2010-12-31 11:59:01
【问题描述】:

我想获得一个具有 Java、Windows、MacOS 和(如果可能的话)Linux 的计算机的唯一 ID。可能是磁盘 UUID、主板 S/N...

Runtime.getRuntime().exec可以用(不是小程序)。

想法?

【问题讨论】:

  • 这是为了反盗版计划吗?
  • 可能是 JNI 调用,没有原生 java
  • 是的,它用于诸如反盗版计划之类的东西,以识别计算机。
  • 任何可以通过 exec() 运行的东西都可以被替换。机器的用户需要做的就是创建一个总是返回预期结果的程序。这只是从工作机器上进行转储并编写一个输出相同内容的程序(例如从文件中)

标签: java uniqueidentifier uuid


【解决方案1】:

MAC地址的问题是可以有很多网络适配器连接到计算机。大多数最新的默认情况下都有两个(wi-fi + 电缆)。在这种情况下,必须知道应该使用哪个适配器的 MAC 地址。我在我的系统上测试了 MAC 解决方案,但我有 4 个适配器(用于 Virtual Box 的电缆、WiFi、TAP 适配器和一个用于蓝牙),我无法决定我应该使用哪个 MAC... 如果有人决定使用适配器当前正在使用(已分配地址)然后出现新问题,因为有人可以拿起他/她的笔记本电脑并从电缆适配器切换到wi-fi。在笔记本电脑通过电缆连接时存储的这种情况下,MAC 现在将无效。

例如,这些是我在系统中找到的适配器:

lo MS TCP Loopback interface
eth0 Intel(R) Centrino(R) Advanced-N 6205
eth1 Intel(R) 82579LM Gigabit Network Connection
eth2 VirtualBox Host-Only Ethernet Adapter
eth3 Sterownik serwera dostepu do sieci LAN Bluetooth

我用来列出它们的代码:

Enumeration<NetworkInterface> nis = NetworkInterface.getNetworkInterfaces();
while (nis.hasMoreElements()) {
    NetworkInterface ni = nis.nextElement();
    System.out.println(ni.getName() + " " + ni.getDisplayName());
}

从这个页面上的选项听,我最能接受,我在我的解决方案中使用的是@Ozhan Duz 的一个,另一个类似于@finnw answer where he used JACOB,并且值得一提的是com4j - 使用 WMI 的示例可用here

ISWbemLocator wbemLocator = ClassFactory.createSWbemLocator();
ISWbemServices wbemServices = wbemLocator.connectServer("localhost","Root\\CIMv2","","","","",0,null);
ISWbemObjectSet result = wbemServices.execQuery("Select * from Win32_SystemEnclosure","WQL",16,null);
for(Com4jObject obj : result) {
    ISWbemObject wo = obj.queryInterface(ISWbemObject.class);
    System.out.println(wo.getObjectText_(0));
}

这将打印一些计算机信息以及计算机序列号。请注意,此示例所需的所有类都必须由 maven-com4j-plugin 生成。 maven-com4j-plugin 的示例配置:

<plugin>
    <groupId>org.jvnet.com4j</groupId>
    <artifactId>maven-com4j-plugin</artifactId>
    <version>1.0</version>
    <configuration>
        <libId>565783C6-CB41-11D1-8B02-00600806D9B6</libId>
        <package>win.wmi</package>
        <outputDirectory>${project.build.directory}/generated-sources/com4j</outputDirectory>
    </configuration>
    <executions>
        <execution>
            <id>generate-wmi-bridge</id>
            <goals>
                <goal>gen</goal>
            </goals>
        </execution>
    </executions>
</plugin>

上面的配置会告诉插件在项目文件夹的target/generated-sources/com4j目录下生成类。

对于那些希望看到即用型解决方案的人,我提供了我为在 Windows、Linux 和 Mac OS 上获取机器 SN 而编写的三个类的链接:

【讨论】:

  • 在 Windows Nano Server 2016 上,格式为“SerialNumber = xxx”。示例代码将永远返回“=”作为序列号。在其他 Windows 安装上,它适用于我。
【解决方案2】:

OSHI 项目提供独立于平台的硬件实用程序。

Maven 依赖:

<dependency>
    <groupId>com.github.oshi</groupId>
    <artifactId>oshi-core</artifactId>
    <version>LATEST</version>
</dependency>

例如,您可以使用类似以下代码的代码来唯一标识一台机器:

import oshi.SystemInfo;
import oshi.hardware.CentralProcessor;
import oshi.hardware.ComputerSystem;
import oshi.hardware.HardwareAbstractionLayer;
import oshi.software.os.OperatingSystem;

class ComputerIdentifier
{
    static String generateLicenseKey()
    {
        SystemInfo systemInfo = new SystemInfo();
        OperatingSystem operatingSystem = systemInfo.getOperatingSystem();
        HardwareAbstractionLayer hardwareAbstractionLayer = systemInfo.getHardware();
        CentralProcessor centralProcessor = hardwareAbstractionLayer.getProcessor();
        ComputerSystem computerSystem = hardwareAbstractionLayer.getComputerSystem();

        String vendor = operatingSystem.getManufacturer();
        String processorSerialNumber = computerSystem.getSerialNumber();
        String processorIdentifier = centralProcessor.getIdentifier();
        int processors = centralProcessor.getLogicalProcessorCount();

        String delimiter = "#";

        return vendor +
                delimiter +
                processorSerialNumber +
                delimiter +
                processorIdentifier +
                delimiter +
                processors;
    }

    public static void main(String[] arguments)
    {
        String identifier = generateLicenseKey();
        System.out.println(identifier);
    }
}

我的机器的输出:

Microsoft#57YRD12#Intel64 Family 6 Model 60 Stepping 3#8

您的输出会有所不同,因为至少处理器序列号会有所不同。

【讨论】:

  • 请注意,其中一些操作需要根访问权限,具体取决于您的操作系统。可能是一个限制因素
  • @user489041 什么操作和什么操作系统?
【解决方案3】:

通常使用MAC地址与网卡相关联。

该地址可通过以下 API 在 Java 6 中使用:

Java 6 Docs for Hardware Address

我没有在 Java 中使用过,但是对于其他网络识别应用程序很有帮助。

【讨论】:

  • 我考虑过,但是当网卡没有连接时,我无法获取任何MAC地址
  • 用户也可以切换网卡。在某些笔记本电脑上,当电池耗尽时,(有线)以太网卡会被禁用以节省电池电量,因此对操作系统不可见。
  • 而且不要忘记,为了欺骗 MAC,甚至不需要更换网卡:aboutlinux.info/2005/09/how-to-change-mac-address-of-your.html
  • 这对我来说不太可行,因为它需要在 linux 上获得 root 权限。
  • 我尝试在虚拟机上使用 MAC 地址,发现它不够稳定。除非您可以保证在 VM 移动和重新启动时保持稳定的 MAC 地址,否则使用 MAC 地址作为机器标识符会给您带来问题。请参阅以下 Bartosz Fiyrn 的答案以获得更好的方法
【解决方案4】:

您想用这个唯一 ID 做什么?也许没有这个 ID 你可以做你想做的事。

MAC 地址可能是一种选择,但这不是受信任的唯一 ID,因为用户可以更改计算机的 MAC 地址。

要在此link 上检查主板或处理器 ID。

【讨论】:

    【解决方案5】:

    仅在 Windows 上,您可以通过JACOB 等 COM 桥接器使用 WMI 获取主板 ID。

    例子:

    import java.util.Enumeration;
    import com.jacob.activeX.ActiveXComponent;
    import com.jacob.com.ComThread;
    import com.jacob.com.EnumVariant;
    import com.jacob.com.Variant;
    
    public class Test {
        public static void main(String[] args) {
            ComThread.InitMTA();
            try {
                ActiveXComponent wmi = new ActiveXComponent("winmgmts:\\\\.");
                Variant instances = wmi.invoke("InstancesOf", "Win32_BaseBoard");
                Enumeration<Variant> en = new EnumVariant(instances.getDispatch());
                while (en.hasMoreElements())
                {
                    ActiveXComponent bb = new ActiveXComponent(en.nextElement().getDispatch());
                    System.out.println(bb.getPropertyAsString("SerialNumber"));
                    break;
                }
            } finally {
                ComThread.Release();
            }
        }
    }
    

    如果你选择使用MAC地址来识别机器,你可以使用WMI来判断一个接口是否通过USB连接(如果你想排除USB适配器)

    也可以通过 WMI 获取硬盘 ID,但这并不可靠。

    【讨论】:

      【解决方案6】:

      使用 MAC 地址作为标识符时要小心。我经历了几个陷阱:

      1. 在 OS X 上,未激活/启动的以太网端口不会显示在 NetworkInterface.getNetworkInterfaces() 枚举中。
      2. 如果您拥有适当的操作系统权限,那么更改卡上的 MAC 地址非常容易。
      3. Java 有不能正确识别“虚拟”接口的习惯。即使使用NetworkInterface.isVirtual() 也不会总是告诉你真相。

      即使存在上述问题,我仍然认为这是硬件锁定许可证的最佳纯 Java 方法。

      【讨论】:

        【解决方案7】:

        不了解您的所有要求。例如,您是想从世界上的所有计算机中唯一地标识一台计算机,还是只是试图从您的应用程序的一组用户中唯一地标识一台计算机。另外,你可以在系统上创建文件吗?

        如果您能够创建文件。您可以创建一个文件并将文件的创建时间用作您的唯一 ID。如果您在用户空间中创建它,那么它将在特定机器上唯一标识您的应用程序的用户。如果您在全局某个地方创建它,那么它可以唯一地识别机器。

        同样,与大多数事情一样,多快就足够快......或者在这种情况下,独特性就足够独特。

        【讨论】:

          【解决方案8】:

          我认为你应该看看这个link ...你可以使用几个 mac+os+hostname+cpu id+motherboard serial number等标识符。

          【讨论】:

          • 您放置在 cpuid/moboserial 后面的链接描述了特定于 Windows 的方式。这不是跨平台的。
          • 在 linux 中,您可以使用以下命令获取硬盘序列号:hdparm -i /dev/sda1 | awk '/SerialNo=/{print $NF}' (只需识别操作系统并尝试不同的方法)您可以使用 lshw 命令找到 MB 序列号
          • 不要指望防病毒软件允许奇怪的 vbs 脚本出现在您的硬盘上。他们中的大多数会在您有机会执行它之前立即阻止该文件。
          【解决方案9】:

          如果任务是记录系统的唯一 ID,则使用 MAC id 是最简单的方法。

          mac id虽然可以改变,但系统其他id的改变也是可以的,只是更换了各自的设备。

          因此,除非不知道唯一 id 需要什么,否则我们可能无法找到合适的解决方案。

          但是,下面的链接有助于提取 mac 地址。 http://www.stratos.me/2008/07/find-mac-address-using-java/

          【讨论】:

            【解决方案10】:

            用于唯一标识 Windows 机器。 确保在使用 wmic 时有替代方法的策略。由于“wmic bios get serialnumber”可能不适用于所有机器,您可能需要其他方法:

            # Get serial number from bios
            wmic bios get serialnumber
            # If previous fails, get UUID
            wmic csproduct get UUID
            # If previous fails, get diskdrive serialnumber
            wmic DISKDRIVE get SerialNumber
            

            资源: 唯一识别 Windows 机器的最佳方法 http://www.nextofwindows.com/the-best-way-to-uniquely-identify-a-windows-machine/

            【讨论】:

              【解决方案11】:

              在我为发布而编写的 java 程序中,我使用了主板序列号(这是我相信 windows 使用的);但是,这仅适用于 Windows,因为我的函数会创建一个临时 VB 脚本,该脚本使用 WMI 来检索值。

              public static String getMotherboardSerial() {
                    String result = "";
                      try {
                        File file = File.createTempFile("GetMBSerial",".vbs");
                        file.deleteOnExit();
                        FileWriter fw = new FileWriter(file);
              
                        String vbs =
                           "Set objWMIService = GetObject(\"winmgmts:\\\\.\\root\\cimv2\")\n"
                          + "Set colItems = objWMIService.ExecQuery _ \n"
                          + "   (\"Select * from Win32_ComputerSystemProduct\") \n"
                          + "For Each objItem in colItems \n"
                          + "    Wscript.Echo objItem.IdentifyingNumber \n"
                          + "Next \n";
              
                        fw.write(vbs);
                        fw.close();
                        Process gWMI = Runtime.getRuntime().exec("cscript //NoLogo " + file.getPath());
                        BufferedReader input = new BufferedReader(new InputStreamReader(gWMI.getInputStream()));
                        String line;
                        while ((line = input.readLine()) != null) {
                           result += line;
                           System.out.println(line);
                        }
                        input.close();
                      }
                      catch(Exception e){
                          e.printStackTrace();
                      }
                      result = result.trim();
                      return result;
                    }
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2019-02-16
                • 2013-07-05
                • 2012-02-23
                • 1970-01-01
                • 2011-03-29
                • 1970-01-01
                相关资源
                最近更新 更多