我是靠谱客的博主 等待铃铛,最近开发中收集的这篇文章主要介绍Java:物联网终端机如何生成唯一识别码1.前言2.首先获取CPU序列号3.MAC地址为什么没用?4.BIOS UUID5.如何缩短编码长度?6.Java代码7.最终效果8.结语参考资料,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

1.前言

  最直接的思路是用CPU的序列号和主板编号来做,但是当你使用:sudo dmidecode -s baseboard-serial-number来获取主板编号时,大部分情况下会给你返回:

To be filled by O.E.M.

  这个提示是令人崩溃的,虽然它可以被服务器的代加工厂任意指定,可是加工厂就是不写。

2.首先获取CPU序列号

  所以目前就剩下CPU的序列号了,CPU的序列号的获取方式很简单。CPU序号也有重复概率,网上有同志反映查到过同一批次服务器可能CPU ID 重复。

  好的,下面我们给出两个主要操作系统下的获取方法。评论区的朋友们可以补充其它系统的,俺没有,就不献丑了。

2.1.Linux

dmidecode -t processor | grep 'ID'

2.2.Windows

wmic cpu get ProcessorId

3.MAC地址为什么没用?

  主要原因是用户在连接多种通讯网络时,会拥有各式各样的Mac地址,使用哪一个都不好。并且心怀不轨的人还可以通过软件进行修改,达到伪装。具体的导论有很多,这里贴一个:How to get a unique computer identifier in Java (like disk ID or motherboard ID)?,这里面就提到,一个答主可以拥有下面这么多MAC地址:

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

4.BIOS UUID

  在关于硬件:在Windows和Linux上使用Python获取唯一的计算机ID一文中提到:在现代PC硬件上,通常在BIOS中存储有一个UUID-在Linux上,有一个命令行实用程序dmidecode可以读取此信息。

  是不是有点眼熟?dmidecode这哥们又出现了,咱们简单介绍一下:

dmidecode在 Linux 系统下获取有关硬件方面的信息。dmidecode 遵循 SMBIOS/DMI 标准,以一种可读的方式dump出机器的DMI(Desktop Management Interface)信息, 其输出的信息包括 BIOS、系统、主板、处理器、内存、缓存等等, 既可以得到当前的配置,也可以得到系统支持的最大配置,比如说支持的最大内存数等。

  好的,下面我们给出两个主要操作系统下的获取方法。评论区的朋友们可以补充其它系统的,俺没有,就不献丑了。

4.1.Linux

dmidecode -t system|grep UUID

4.2.Windows

wmic path win32_computersystemproduct get uuid

5.如何缩短编码长度?

  现在CPU IDBIOS UUID拼接在一起,已经52位长了,如果我们需要把它变成一个类似于1分钱优惠券激活码的东西让用户手动输入就太长了。

  这个时候,我们需要进行摘要,摘要算法有哪些呢?有MD5(Message Digest)SHA(Secure Hash Algorithm)HMAC(Hash-based Message Authentication Code)。记住一个简易技术选型方法——先试试MD5行不行,不行再说。

6.Java代码

6.1.MachineCodeUtil.java

public class MachineCodeUtil {

    public static final String LINUX_OS_NAME = "LINUX";
    public static final String SYSTEM_PROPERTY_OS_NAME = "os.name";

    public static void main(String[] args) {
        System.out.println(getThisMachineCode());
        System.out.println(getThisMachineCodeMd5());
    }

    /**
     * 获取机器唯一识别码(CPU ID + BIOS UUID)
     *
     * @return 机器唯一识别码
     */
    public static String getThisMachineCode() {
        try {
            return getCpuId() + getBiosUuid();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }

    /**
     * 获取机器码进行MD5摘要后的字符串
     *
     * @return
     */
    public static String getThisMachineCodeMd5() {
        try {
            String thisMachineCode = getThisMachineCode();
            String md5Upper = MD5Utils.MD5Upper(thisMachineCode);
            return md5Upper;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }

    /**
     * 获取当前系统CPU序列,可区分linux系统和windows系统
     */
    public static String getCpuId() throws IOException {
        String cpuId;
        // 获取当前操作系统名称
        String os = System.getProperty(SYSTEM_PROPERTY_OS_NAME);
        os = os.toUpperCase();

        if (LINUX_OS_NAME.equals(os)) {
            cpuId = getLinuxDmidecodeInfo("dmidecode -t processor | grep 'ID'", "ID", ":");
        } else {
            cpuId = getWindowsCpuId();
        }
        return cpuId.toUpperCase().replace(" ", "");
    }

    /**
     * 获取linux系统
     * dmidecode
     * 命令的信息
     */
    public static String getLinuxDmidecodeInfo(String cmd, String record, String symbol) throws IOException {
        String execResult = executeLinuxCmd(cmd);
        String[] infos = execResult.split("n");
        for (String info : infos) {
            info = info.trim();
            if (info.contains(record)) {
                info.replace(" ", "");
                String[] sn = info.split(symbol);
                return sn[1];
            }
        }
        return null;
    }


    /**
     * 执行Linux 命令
     *
     * @param cmd Linux 命令
     * @return 命令结果信息
     * @throws IOException 执行命令期间发生的IO异常
     */
    public static String executeLinuxCmd(String cmd) throws IOException {
        Runtime run = Runtime.getRuntime();
        Process process;
        process = run.exec(cmd);
        InputStream processInputStream = process.getInputStream();
        StringBuilder stringBuilder = new StringBuilder();
        byte[] b = new byte[8192];
        for (int n; (n = processInputStream.read(b)) != -1; ) {
            stringBuilder.append(new String(b, 0, n));
        }
        processInputStream.close();
        process.destroy();
        return stringBuilder.toString();
    }

    /**
     * 获取windows系统CPU序列
     */
    public static String getWindowsCpuId() throws IOException {
        Process process = Runtime.getRuntime().exec(
                new String[]{"wmic", "cpu", "get", "ProcessorId"});
        process.getOutputStream().close();
        Scanner sc = new Scanner(process.getInputStream());
        sc.next();
        String serial = sc.next();
        return serial;
    }

    /**
     * 获取 BIOS UUID
     *
     * @return BIOS UUID
     * @throws IOException 获取BIOS UUID期间的IO异常
     */
    public static String getBiosUuid() throws IOException {
        String cpuId;
        // 获取当前操作系统名称
        String os = System.getProperty("os.name");
        os = os.toUpperCase();

        if ("LINUX".equals(os)) {
            cpuId = getLinuxDmidecodeInfo("dmidecode -t system | grep 'UUID'", "UUID", ":");
        } else {
            cpuId = getWindowsBiosUUID();
        }
        return cpuId.toUpperCase().replace(" ", "");
    }

    /**
     * 获取windows系统 bios uuid
     *
     * @return
     * @throws IOException
     */
    public static String getWindowsBiosUUID() throws IOException {
        Process process = Runtime.getRuntime().exec(
                new String[]{"wmic", "path", "win32_computersystemproduct", "get", "uuid"});
        process.getOutputStream().close();
        Scanner sc = new Scanner(process.getInputStream());
        sc.next();
        String serial = sc.next();
        return serial;
    }

}

6.2.MD5Utils.java

  这一部分完全copy自Java MD5 加密工具类。

/**
 * MD5加密/验证工具类
 *
 */
public class MD5Utils {
	
	static final char hexDigits[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
	static final char hexDigitsLower[] = { '0', '1', '2', '3', '4', '5', '6', '7','8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
	
	/**
	  *   对字符串 MD5 无盐值加密
	 *   
	 * @param plainText
	 * 		传入要加密的字符串
	 * @return
	 *  	MD5加密后生成32位(小写字母+数字)字符串
	 */
	public static String MD5Lower(String plainText) {
		try {
			// 获得MD5摘要算法的 MessageDigest 对象
			MessageDigest md = MessageDigest.getInstance("MD5");
			
			// 使用指定的字节更新摘要
			md.update(plainText.getBytes());
			
			// digest()最后确定返回md5 hash值,返回值为8位字符串。因为md5 hash值是16位的hex值,实际上就是8位的字符
            // BigInteger函数则将8位的字符串转换成16位hex值,用字符串来表示;得到字符串形式的hash值。1 固定值
			return new BigInteger(1,  md.digest()).toString(16);
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
			return null;
		}
	}
	
	
	
	/**
	  *  对字符串 MD5 加密
	 * 
	 * @param plainText
	 * 		传入要加密的字符串
	 * @return
	 * 		MD5加密后生成32位(大写字母+数字)字符串
	 */
	public static String MD5Upper(String plainText) {
		try {
			// 获得MD5摘要算法的 MessageDigest 对象
			MessageDigest md = MessageDigest.getInstance("MD5");
			
			// 使用指定的字节更新摘要
			md.update(plainText.getBytes());
			
			// 获得密文
			byte[] mdResult = md.digest();
			// 把密文转换成十六进制的字符串形式
			int j = mdResult.length;
			char str[] = new char[j * 2];
			int k = 0;
			for (int i = 0; i < j; i++) {
				byte byte0 = mdResult[i];
				str[k++] = hexDigits[byte0 >>> 4 & 0xf];// 取字节中高 4 位的数字转换, >>> 为逻辑右移,将符号位一起右移
				str[k++] = hexDigits[byte0 & 0xf]; // 取字节中低 4 位的数字转换
			}
			return new String(str);
		} catch (Exception e) {
			e.printStackTrace();
            return null;
		}
	}
	
	/**
	 *   对字符串 MD5 加盐值加密
	 *   
	 * @param plainText
	 * 		传入要加密的字符串
	 * @param saltValue
	 * 		传入要加的盐值
	 * @return
	 *  	MD5加密后生成32位(小写字母+数字)字符串
	 */
	public static String MD5Lower(String plainText, String saltValue) {
		try {
			// 获得MD5摘要算法的 MessageDigest 对象
			MessageDigest md = MessageDigest.getInstance("MD5");
			
			// 使用指定的字节更新摘要
			md.update(plainText.getBytes());
			md.update(saltValue.getBytes());
			
			// digest()最后确定返回md5 hash值,返回值为8位字符串。因为md5 hash值是16位的hex值,实际上就是8位的字符
			// BigInteger函数则将8位的字符串转换成16位hex值,用字符串来表示;得到字符串形式的hash值。1 固定值
			return new BigInteger(1,  md.digest()).toString(16);
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
			return null;
		}
	}
	
	/**
	 *   对字符串 MD5 加盐值加密
	 *   
	 * @param plainText
	 * 		传入要加密的字符串
	 * @param saltValue
	 * 		传入要加的盐值
	 * @return
	 *  	MD5加密后生成32位(大写字母+数字)字符串
	 */
	public static String MD5Upper(String plainText, String saltValue) {
		try {
			// 获得MD5摘要算法的 MessageDigest 对象
			MessageDigest md = MessageDigest.getInstance("MD5");
			
			// 使用指定的字节更新摘要
			md.update(plainText.getBytes());
			md.update(saltValue.getBytes());
			
			// 获得密文
			byte[] mdResult = md.digest();
			// 把密文转换成十六进制的字符串形式
			int j = mdResult.length;
			char str[] = new char[j * 2];
			int k = 0;
			for (int i = 0; i < j; i++) {
				byte byte0 = mdResult[i];
				str[k++] = hexDigits[byte0 >>> 4 & 0xf];
				str[k++] = hexDigits[byte0 & 0xf];
			}
			return new String(str);
		} catch (Exception e) {
			e.printStackTrace();
            return null;
		}
	}
	
    /**
     *  MD5加密后生成32位(小写字母+数字)字符串
          *    同 MD5Lower() 一样
     */
    public final static String MD5(String plainText) {
        try {
            MessageDigest mdTemp = MessageDigest.getInstance("MD5");
            
            mdTemp.update(plainText.getBytes("UTF-8"));
            
            byte[] md = mdTemp.digest();
            int j = md.length;
            char str[] = new char[j * 2];
            int k = 0;
            for (int i = 0; i < j; i++) {
                byte byte0 = md[i];
                str[k++] = hexDigitsLower[byte0 >>> 4 & 0xf];
                str[k++] = hexDigitsLower[byte0 & 0xf];
            }
            return new String(str);
        } catch (Exception e) {
            return null;
        }
    }
    
    /**
          *  校验MD5码
     * 
     * @param text
     *      	要校验的字符串
     * @param md5
     *            md5值
     * @return 校验结果
     */
    public static boolean valid(String text, String md5) {
        return md5.equals(MD5(text)) || md5.equals(MD5(text).toUpperCase());
    }
}

7.最终效果

  最终,你会获得类似于下面这样的字符串:

B6C15A6BF77C90244115E8E7B623F34C

  当然了,如果你喜欢,可以每四位添加一个横杠,就像下面这样:

B6C1-5A6B-F77C-9024-4115-E8E7-B623-F34C

  是不是有那味儿了?感觉下一秒钟就要拿着优惠券购买玛莎拉蒂了?

8.结语

  另外,如果您能够保证用户不更换硬盘,硬盘的ID真的是不错的选择。

  当我们获取到当前设备的唯一识别码,我们可以做很多有价值的事情。其实最有价值的还是去重,若后期有更好的方法,我也会分享给大家。希望看完博文的你没有bug。

参考资料

排名不分先后:

  • How to Get the BIOS UUID
  • dmidecode命令
  • 使用Java实现信息摘要算法
  • 主板型号:to be filled by O.E.M,这是什么情况?
  • How to uniquely identify computer using C#?

最后

以上就是等待铃铛为你收集整理的Java:物联网终端机如何生成唯一识别码1.前言2.首先获取CPU序列号3.MAC地址为什么没用?4.BIOS UUID5.如何缩短编码长度?6.Java代码7.最终效果8.结语参考资料的全部内容,希望文章能够帮你解决Java:物联网终端机如何生成唯一识别码1.前言2.首先获取CPU序列号3.MAC地址为什么没用?4.BIOS UUID5.如何缩短编码长度?6.Java代码7.最终效果8.结语参考资料所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(43)

评论列表共有 0 条评论

立即
投稿
返回
顶部