一种软件license授权设计案例

一种软件license授权设计案例

整体设计思路

license服务器端:
--负责根据客户端systemSign颁发证书。
--使用dom4j生成lic.xml证书
--使用AES对xml关键节点进行数据加密
--lic证书生成时设定信息包括:
-----客户端systemSign
-----生效起始时间
-----生效截止时间
-----上一次校验时间
-----项目版本号
-----license文件生成路径

license客户端:
--负责生成systemSign客户端系统签名
--证书检验/定时验证/自助更新(手动替换)
--API管控(无lic证书,则无法访问系统功能API)
--证书校验逻辑:
-----lic.xml文件存不存在
-----解析xml是否异常!
-----解密signature签名是否成功
-----解析版本号、lic生成时间、lic过期时间、上一次校验时间
-----校验本机app版本号与license版本号是否不一致
-----校验mac地址与本机是否一致
-----校验cpu序列号与本机是否一致
---证书过期判定:
------上次校验时间 大于当前系统时间
------lic证书生成时间 大于当前系统时间
------lic证书过期时间 小于当前系统时间

需要引入的依赖

 		<dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.11</version>
        </dependency>
 		<dependency>
            <groupId>dom4j</groupId>
            <artifactId>dom4j</artifactId>
            <version>1.6.1</version>
        </dependency>
        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>28.2-jre</version>
        </dependency>        

License客户端

硬件识别

linux识别

LinuxCmd.java 通过bash命令得到需要的硬件信息

package cn.test.lic.hardware;

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.util.Arrays;
import java.util.List;

/**
 *
 * 这里使用bash命令操作 dmidecode \ ip 等命令 返回需要的硬件信息
 */
public class LinuxCmd {
   


//    public static void main(String[] args) throws IOException {
   
//        String serialNumber = getSerialNumber();
//        String cpuNumber = getCpuNumber();
//        String mac = getMAC();
//        System.out.println(serialNumber);
//        System.out.println(cpuNumber);
//        System.out.println(mac);
//    }

    /**
     * 获取MAC地址
     * @return 80:61:5f:13:93:29
     * @throws IOException
     */
    public static String getMAC() throws IOException {
   
        //[root@localhost ~]# ip addr show |grep 'link/ether'
        //    link/ether 80:61:5f:13:93:29 brd ff:ff:ff:ff:ff:ff
        //    link/ether 80:61:5f:13:93:2a brd ff:ff:ff:ff:ff:ff
        //    link/ether 52:54:00:d6:1d:db brd ff:ff:ff:ff:ff:ff
        //    link/ether 52:54:00:d6:1d:db brd ff:ff:ff:ff:ff:ff
        //    link/ether 02:42:1b:79:ee:e9 brd ff:ff:ff:ff:ff:ff
        String desc = exec("ip addr show |grep 'link/ether'");
        String[] split = desc.split("\n");
        List<String> list = Arrays.asList(split);
        if (list.size() > 0) {
   
            String s = list.get(0);
            System.out.println(s);
            String[] s1 = s.split(" ");
            String s2 = s1[1];
            System.out.println(s2);
            return s2;
        } else {
   
            return "";
        }
    }


    //-------------------------------------------------------------
    // dmidecode 是linux系统提供的查看cpu相关硬件信息的工具
    //-----------------------------------------

    /**
     * 获取linux的 Cpu ID
     *
     * @return String 11 0F 90 00 FF FB 8B 17
     * @throws IOException
     */
    public static String getCpuNumber() throws IOException {
   
        String desc = exec("dmidecode -t processor | grep 'ID'");
        return handleBashRespStr(desc);
    }

    /**
     * 获取linux 序列号
     *
     * @return String  CD66393F
     * @throws IOException
     */
    public static String getSerialNumber() throws IOException {
   
        String desc = exec("dmidecode | grep 'Serial Number'");
        return handleBashRespStr(desc);
    }




    private static String handleBashRespStr(String desc) {
   
        String[] split = desc.split("\n");
        List<String> list = Arrays.asList(split);
        if (list.size() > 0) {
   
            String s = list.get(0);
            String[] split1 = s.split(":");
            String s1 = split1[1];
            System.err.println(s1);
            return s1;
        } else {
   
            return "";
        }
    }

    /**
     * 执行linux bash命令
     *
     * @param bash 如 ifconfig
     * @return String
     * @throws IOException
     */
    private static String exec(String bash) throws IOException {
   
        String[] cmdA = {
   "/bin/sh", "-c", bash};
        Process process = Runtime.getRuntime().exec(cmdA);
        LineNumberReader br = new LineNumberReader(new InputStreamReader(process.getInputStream()));
        StringBuffer sb = new StringBuffer();
        String line;

        while ((line = br.readLine()) != null) {
   
            System.out.println(line);
            line = line.trim();

            if (line.length() > 0) {
   
                sb.append(line).append("\n");
            }
        }
        return sb.toString();
    }
}

windows识别

WmicCmd.java利用cmd命令操作wmic返回需要的硬件信息

package cn.test.lic.hardware;


import java.io.IOException;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.util.Arrays;
import java.util.List;

/**
 * wmic是windows系统内置的查看硬件信息的工具
 * 这里利用cmd命令操作wmic返回需要的硬件信息
 */
public class WmicCmd {
   

    private static String execCmd(String cmd) throws IOException {
   

        String[] cmdA = {
   "cmd.exe","/c",cmd};
        Process process = Runtime.getRuntime().exec(cmdA);
        LineNumberReader br = new LineNumberReader(new InputStreamReader(process.getInputStream(),"GBK"));
        StringBuffer sb  = new StringBuffer();
        String line;

        while ((line=br.readLine())!=null){
   
            line = line.trim();
            if (line.length()>0) {
   
                sb.append(line).append("\n");
            }
        }
        return sb.toString();

    }

    private static String handleCmdRespStr(String desc){
   
        String[] split = desc.split("\n");
        List<String> list = Arrays.asList(split);
        if (list.size()>1){
   
            return list.get(1).trim();
        }else {
   
            return "";
        }
    }

    /**
     * 获取mac地址
     * @return String  MACAddress
     * 8C:EC:4B:55:0E:EC
     * 20:41:53:59:4E:FF
     * @throws IOException
     */
    public static String getMacAddress() throws IOException {
   
        final String cmd  = "wmic nicconfig get macaddress";
        String desc = execCmd(cmd);
        return handleCmdRespStr(desc);
    }

    /**
     * 获取cpuId
     * @return String  ProcessorId
     * BFEBFBFF000906E9
     * @throws IOException
     */
    public static String getCpuProcessorId() throws IOException {
   
        final String cmd  = "wmic cpu get processorid";
        String desc = execCmd(cmd);
        return handleCmdRespStr(desc);
    }

    /**
     * 获取bios序列号
     * @return SerialNumber
     *         H34C4N2
     * @throws IOException
     */
    public static String getBiosSerialNumber() throws IOException {
   
        final String cmd  = "wmic bios get serialnumber";
        String desc = execCmd(cmd);
        return handleCmdRespStr(desc);
    }

    /**
     * 获取 主板序列号
     * @return String  SerialNumber
     *                 /H34C4N2/CNWS2007CN02YV/
     * @throws IOException
     */
    public static String getBaseBoardSerialNumber() throws IOException {
   
        final String cmd  = "wmic baseboard get serialnumber";
        String desc = execCmd(cmd);
        return handleCmdRespStr(desc);
    }



}

工具类

AES工具类
package cn.test.lic.util;



import cn.hutool.core.codec.Base64;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.spec.SecretKeySpec;
import java.security.SecureRandom;

public class AESjjmUtils {
   


    /**
     * 定义1个默认的aes key
     */
    private static final String DEFAULT_AES_SEAD_KEY = "20230609";

    /**
     * 使用默认key快速加密
     * @param ywStr String 原文
     * @return String
     * @throws Exception
     */
    public static String fastEncrypt(String ywStr) throws Exception {
   
        return encrypt(ywStr,DEFAULT_AES_SEAD_KEY);
    }

    /**
     * 使用默认key快速解密
     * @param mwStr String 密文
     * @return String
     * @throws Exception
     */
    public static String fastDecrypt(String mwStr) throws Exception {
   
        return decrypt(mwStr,DEFAULT_AES_SEAD_KEY);
    }


    /**
     * AES 加密
     * @param ywStr  原文
     * @param aesSeedKey 加密key
     * @return String
     * @throws Exception
     */
    public static String encrypt(String ywStr, String aesSeedKey) throws Exception {
   
        SecretKeySpec spec = getAesSecretKeySpec(aesSeedKey);
        //实例化Cipher
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        //使用密钥初始化,设置为加密模式
        cipher.init(Cipher.ENCRYPT_MODE, spec);
        byte[] byteContent = ywStr.getBytes("utf-8");
        byte[] result = cipher.doFinal(byteContent);
        String aesMw = Base64.encode(result);
        return aesMw;
    }

    /**
     * AES 解密
     * @param mwStr  密文
     * @param aesSeedKey 加密key
     * @return String
     */
    public static String decrypt(String mwStr,String aesSeedKey) throws Exception {
   
        SecretKeySpec spec = getAesSecretKeySpec(aesSeedKey);
        //实例化 Cipher
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        //使用密钥初始化,设置为解密模式
        cipher.init(Cipher.DECRYPT_MODE,spec);
        byte[] decodeBytes = Base64.decode(mwStr);
        byte[] result = cipher.doFinal(decodeBytes);
        String resStr = new String(result, "utf-8");
        return resStr;
    }


    private static SecretKeySpec getAesSecretKeySpec(String aesSeedKey)throws Exception{
   
        //AES 要求密钥长度为 128
        SecureRandom random = SecureRandom.getInstance("SHA1PRNG", "SUN");
        random.setSeed(aesSeedKey.getBytes());
        //利用seed值,生成1个128位的key
        KeyGenerator kg = KeyGenerator.getInstance("AES");
        kg.init(128, random);
        //生成一个密钥
        return new SecretKeySpec(kg.generateKey().getEncoded(), "AES");
    }



}
统一硬件工具类

UniHardwareUtil.java

package cn.test.lic.util;


import cn.test.lic.hardware.LinuxCmd;
import cn.test.lic.hardware.WmicCmd;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;

@Slf4j
public class UniHardwareUtil {
   

    public static String getMacAddr() throws IOException {
   
        String property = System.getProperty("os.name");
        if (property.contains("Window")) {
   
            String mac = WmicCmd
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ThinkPet

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值