Sfoglia il codice sorgente

feat: 授权模块制作

kindring 1 anno fa
parent
commit
d44ff9c73c

+ 0 - 1
authorize/authorize.hfy

@@ -1 +0,0 @@
-dDZzV05ybXhHNE1rUkt0UGFLVmZjQ0tUZmNVYS92bWRERU1mNWpKK0w5ZHMwVnV0UmVIRzBOWXMwSG9iS21tMXNYN3FpKzR6dTB3SXBTSHJ2dVNKMlhvdEhUdStkNFBHcUdpcmRHRmZMTm9ZMk40UnB6TytRRGswcFlkSEtPM3dpdVovakN2YzZoK3FhVHZUOVpNTFh4alkzaEduTTc1QU9UU2xoMGNvN2ZESDdsd3BsL2xVYTF1Vk0rUkxTbTIx

+ 72 - 8
src/main/java/com/genersoft/iot/vmp/VManageBootstrap.java

@@ -1,18 +1,25 @@
 package com.genersoft.iot.vmp;
 
+import com.genersoft.iot.vmp.conf.AuthorRun;
+import com.genersoft.iot.vmp.conf.AuthorizeApprove;
+import com.genersoft.iot.vmp.conf.UserSetting;
 import com.genersoft.iot.vmp.conf.druid.EnableDruidSupport;
 import com.genersoft.iot.vmp.conf.exception.ControllerException;
+import com.genersoft.iot.vmp.conf.redis.RedisConfig;
 import com.genersoft.iot.vmp.utils.GitUtil;
 import com.genersoft.iot.vmp.utils.SpringBeanFactory;
 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.boot.builder.SpringApplicationBuilder;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
 import org.springframework.boot.web.servlet.ServletComponentScan;
 import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
 import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.context.annotation.ComponentScan;
 import org.springframework.scheduling.annotation.EnableScheduling;
 
 import javax.servlet.ServletContext;
@@ -22,6 +29,7 @@ import javax.servlet.SessionTrackingMode;
 import java.util.Collections;
 
 import com.genersoft.iot.vmp.conf.Authorize;
+import org.springframework.scheduling.quartz.SpringBeanJobFactory;
 
 /**
  * 启动类
@@ -34,24 +42,80 @@ public class VManageBootstrap extends SpringBootServletInitializer {
 
 	private final static Logger logger = LoggerFactory.getLogger(VManageBootstrap.class);
 
-	private Authorize authorize = new Authorize();
+//	private Authorize authorize = Authorize.(Authorize.baseAuthorizeFilePath);
+
 	private static String[] args;
 	private static ConfigurableApplicationContext context;
 	public static void main(String[] args) {
-		logger.info("start");
-		VManageBootstrap.args = args;
-		VManageBootstrap.context = SpringApplication.run(VManageBootstrap.class, args);
-		GitUtil gitUtil1 = SpringBeanFactory.getBean("gitUtil");
+		// 输出启动参数
+//		logger.info("启动参数:");
+		String param_passwd = null;
+		String param_mc = null;
+		String param_company = null;
 		logger.info("--------------------------------------------------");
 		logger.info("------------- HFY GB Server START ----------------");
 		logger.info("--------------------------------------------------");
+		for (String arg : args) {
+			// 获取passwd参数 (授权密码)
+			if (arg.startsWith("-passwd=")) {
+				param_passwd = arg.substring(8);
+			}
+			// 获取company参数 (公司名)
+			if (arg.startsWith("-company=")) {
+				param_company = arg.substring(9);
+			}
+
+		}
+		if (param_passwd == null) {
+			logger.error("请输入授权密码");
+			return;
+		}
+		if (param_company == null) {
+			logger.error("请输入公司名");
+			return;
+		}
+		// 检查授权文件是否存在
+		if (!Authorize.checkAuthorizeFile(Authorize.baseAuthorizeFilePath))
+		{
+			logger.info("---------------------------------------------");
+			logger.warn("!!!!!!!!!!!!!!! 没有申请授权文件 !!!!!!!!!!!!!!!");
+			logger.info("---------------------------------------------");
+			logger.info("--------------- 正在生成授权文件 ---------------");
+			logger.info("---------------------------------------------");
+			// 获取用户授权密码, 生成授权文件
+			Authorize.generateAuthorizeFile(Authorize.baseAuthorizeFilePath, param_company, param_passwd);
+			return;
+		}
+		// 授权请求数据
+		AuthorRun authorRun = new AuthorRun(
+				Authorize.baseAuthorizeFilePath,
+				AuthorizeApprove.baseAuthorizeApproveFilePath);
+		if(!authorRun.isAuthorize()) {
+			logger.info("---------------------------------------------");
+			logger.info("--------------- 无法解析批准文件 ---------------");
+			logger.info("---------------------------------------------");
+			return;
+		}
+		VManageBootstrap.args = args;
+		VManageBootstrap.context = SpringApplication.run(VManageBootstrap.class, args);
+		// 判断是否已经申请授权文件
+
+
+		GitUtil gitUtil1 = SpringBeanFactory.getBean("gitUtil");
 		logger.info("构建版本: {}", gitUtil1.getBuildVersion());
 		logger.info("构建时间: {}", gitUtil1.getBuildDate());
 		logger.info("GIT最后提交时间: {}", gitUtil1.getCommitTime());
-		logger.info("机器码: {}", Authorize.getMachineCode());
-//		Authorize.generateAuthorizeFile(Authorize.baseAuthorizeFilePath, "{\"com\":\"深圳合方圆\",\"machineCode\":\"12402306B27BB6D9118EC29224DD3FCDD41D8CD98F00B204E9800998ECF8427ED41D8CD98F00B204E9800998ECF8427E\"}");
+
+		// 从 UserSetting 中获取用户授权密码
 		logger.info("--------------------------------------------------");
-		Authorize.decryptAuthorizeFile(Authorize.baseAuthorizeFilePath);
+		logger.info("--------------------------------------------------");
+
+	}
+
+
+	public static void stopServer() {
+		// 停止 redis
+		System.exit(0);
 	}
 	// 项目重启
 	public static void restart() {

+ 5 - 1
src/main/java/com/genersoft/iot/vmp/conf/authorData.java → src/main/java/com/genersoft/iot/vmp/conf/AuthorData.java

@@ -1,15 +1,19 @@
 package com.genersoft.iot.vmp.conf;
 
 
-public class authorData {
+public class AuthorData {
     // 机器码
     private String machineCode;
+
     // 公司名
     private String company;
+
     // 随机码
     private String authorizeCode;
+
     // 授权申请时间
     private String authorizeTime;
+
     // 用户密码, 用于程序运行
     private String password;
 

+ 158 - 0
src/main/java/com/genersoft/iot/vmp/conf/AuthorRun.java

@@ -0,0 +1,158 @@
+package com.genersoft.iot.vmp.conf;
+
+import com.genersoft.iot.vmp.utils.DateUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class AuthorRun {
+    // 机器码
+    private static String machineCode = "";
+    // 上次检测时间
+    private static String lastCheckTime = "";
+    // 程序运行时间戳
+    private static String runTime = "";
+
+    // 剩余授权天数
+    private static int authorizeDay = 0;
+
+    private AuthorData authorData;
+    private AuthorizeApprove authorizeApprove;
+
+    private String MachineCode = "";
+
+    // 是否已经被批准授权
+    private boolean isAuthorize = true;
+
+    private String authorizeFilePath = Authorize.baseAuthorizeFilePath;
+    private String authorizeApproveFilePath = AuthorizeApprove.baseAuthorizeApproveFilePath;
+    public AuthorRun(String _authorizeFilePath, String _authorizeApproveFilePath) {
+        this.authorizeFilePath = _authorizeFilePath;
+        this.authorizeApproveFilePath = _authorizeApproveFilePath;
+        // 获取机器码
+        this.MachineCode = Authorize.getMachineCode();
+        // 读取授权文件
+        this.authorData = Authorize.parseBaseAuthorizeFile(MachineCode, this.authorizeFilePath);
+        // 读取授权批准文件
+        this.authorizeApprove = AuthorizeApprove.parseAuthorizeApprove(
+                this.authorizeApproveFilePath,
+                MachineCode,
+                this.authorData);
+
+        this.isAuthorize = true;
+        if(this.authorizeApprove == null) {
+            logger.error("授权批准文件为空, 无法解析");
+            this.isAuthorize = false;
+            return ;
+        }
+        // 检查授权是否合法
+        if(!this.checkAuthorize()) {
+            logger.error("授权不合法");
+            this.isAuthorize = false;
+            return;
+        }
+        // 获取剩余授权天数
+       int lastDay = computeAuthorizeDay();
+       if(lastDay <= 0)
+       {
+          logger.error("当前程序授权已过期");
+          return;
+       }
+
+
+    }
+    // 检查授权是否有效
+    public boolean checkAuthorize(){
+        // 检测当前设备是否与授权文件机器码一致
+        if(!Authorize.getMachineCode().equals(this.MachineCode)) {
+            logger.error("授权机器码不一致");
+            return false;
+        }
+        // 检测机器码是否一致
+        if(!this.authorData.getMachineCode().equals(this.authorizeApprove.getMachineCode())) {
+            logger.error("授权机器码不一致");
+            return false;
+        }
+        // 判断请求时间是否等于请求时间
+        if(!this.authorData.getAuthorizeTime().equals(this.authorizeApprove.getRequestTime())) {
+            logger.error("授权时间不一致");
+            return false;
+        }
+
+        // 检测授权请求时间是否小于授权批准时间
+        long queryTime = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(this.authorData.getAuthorizeTime());
+        long approveTime = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(this.authorizeApprove.getApproveTime());
+        if(queryTime > approveTime) {
+            logger.error("授权批准时间不合法");
+            return false;
+        }
+        return true;
+    }
+
+    // 计算剩余授权天数 基于 授权批准文件 来进行计算, 批准当天不计算
+    //
+
+    /**
+     * 计算剩余授权天数(天) 当前时间 - 批准时间 + 1 = 剩余授权天数
+     * @return 剩余授权天数 (天)
+     */
+    public int computeAuthorizeDay() {
+        // 获取授权批准时间
+        String approveTime = this.authorizeApprove.getApproveTime();
+        // 获取授权天数
+        int authorizeDay = this.authorizeApprove.getAuthorizeDay();
+        // 获取当前时间
+        String nowTime = DateUtil.getNowForISO8601();
+        // 获取授权批准时间戳
+        long approveTimestamp = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(approveTime);
+        // 获取当前时间戳
+        long nowTimestamp = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(nowTime);
+        // 计算授权天数
+        int day = (int)((nowTimestamp - approveTimestamp) / (24 * 60 * 60));
+        // 计算剩余授权天数
+        int remainDay = authorizeDay - day;
+        return remainDay;
+    }
+
+
+    public static String getMachineCode() {
+        return machineCode;
+    }
+
+    public static void setMachineCode(String machineCode) {
+        AuthorRun.machineCode = machineCode;
+    }
+
+    public static String getLastCheckTime() {
+        return lastCheckTime;
+    }
+
+    public static void setLastCheckTime(String lastCheckTime) {
+        AuthorRun.lastCheckTime = lastCheckTime;
+    }
+
+    public static String getRunTime() {
+        return runTime;
+    }
+
+    public static void setRunTime(String runTime) {
+        AuthorRun.runTime = runTime;
+    }
+
+    public static int getAuthorizeDay() {
+        return authorizeDay;
+    }
+
+    public static void setAuthorizeDay(int authorizeDay) {
+        AuthorRun.authorizeDay = authorizeDay;
+    }
+
+    public boolean isAuthorize() {
+        return isAuthorize;
+    }
+
+    private final static String baseAuthorizeApproveFilePath = "authorize/authorizeApprove.hfy";
+
+    private final static Logger logger = LoggerFactory.getLogger(Authorize.class);
+
+
+}

+ 141 - 42
src/main/java/com/genersoft/iot/vmp/conf/Authorize.java

@@ -8,34 +8,39 @@ import com.genersoft.iot.vmp.VManageBootstrap;
 import net.roseboy.classfinal.util.*;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.util.Base64Utils;
 
 import java.io.*;
-
+import com.genersoft.iot.vmp.utils.DateUtil;
+import com.genersoft.iot.vmp.utils.Md5Utils;
 import java.util.List;
 import java.util.Scanner;
 
+
 // 程序授权类. 用于控制程序的使用权限.
 public class Authorize {
 
+
 //    调用 lib/classfinal-fatjar.jar 中的方法. 用于获取机器码
-    private final static Logger logger = LoggerFactory.getLogger(VManageBootstrap.class);
+    private final static Logger logger = LoggerFactory.getLogger(Authorize.class);
 
+    private static String upCompany = "szhfy";
 
     public static String baseAuthorizeFilePath = "authorize/authorize.hfy";
 
+    public static String baseMachineFilePath = "authorize/MachineCode.hfy";
+
+    // 授权请求文件路径 (用于请求授权)
     private String authorizeFilePath = "authorize/authorize.hfy";
 
-    /**
-     * 生成机器码 96 位
-     */
-    public static String getMachineCode() {
-        String code = new String(SysUtils.makeMarchinCode());
-        return code;
+
+    Authorize(String authorizeFilePath) {
+        this.authorizeFilePath = authorizeFilePath;
     }
 
     // 读取授权文件
-    public static byte[] readAuthorizeFile(String path) {
+    private static byte[] readAuthorizeFile(String path) {
         if(path == null) {
             path = baseAuthorizeFilePath;
         }
@@ -46,40 +51,77 @@ public class Authorize {
             return null;
         }
         byte[] data = IoUtils.readFileToByte(file);
-//        String code = new String(data);
-//        logger.info("code: {}", code);
-//        if(code.length() == 0) {
-//            return null;
-//        }
         // 解析授权文件
         return data;
     }
 
+    /**
+     * 生成机器码 96 位
+     */
+    public static String getMachineCode() {
+        String code = new String(SysUtils.makeMarchinCode());
+        return code;
+    }
+
+    public static String getAuthorizePasswd(String machineCode){
+        return machineCode.substring(16, 32) + machineCode + machineCode.substring(64, 80);
+    }
+
+    // 检查授权文件是否存在
+    public static boolean checkAuthorizeFile(String path) {
+        if(path == null) {
+            path = baseAuthorizeFilePath;
+        }
+        File file = new File(path);
+        if(!file.exists()) {
+            return false;
+        }
+        return true;
+    }
+
+
+    /**
+     * 获取授权文件密文
+     * @param authorizePath 授权文件路径
+     * @return
+     */
+    public static String getEncryptAuthorData(String authorizePath) {
+        byte[] authorizeCode = readAuthorizeFile(authorizePath);
+        if (authorizeCode == null || authorizeCode.length == 0) {
+            logger.error("授权文件读取失败. 请检查授权文件是否存在. ");
+            return null;
+        }
+        // 使用 base64 转换文本
+        byte[] data = Base64Utils.encode(authorizeCode);
+        String code = new String(data);
+        logger.info("code: {}", code);
+        return code;
+    }
+
     /**
      * 解密授权文件
      * @param authorizePath 授权文件路径
      * @return
      */
-    public static String decryptAuthorizeFile(String authorizePath) {
+    public static String decryptAuthorizeFile(String machineCode, String authorizePath) {
+        byte[] authorizeCode = readAuthorizeFile(authorizePath);
+        if (machineCode == null) {
+            logger.error("机器码解析失败");
+            return null;
+        }
+        if(authorizeCode == null || authorizeCode.length == 0) {
+            logger.error("授权文件读取失败. 请检查授权文件是否存在. ");
+            return null;
+        }
         try{
-            String machineCode = getMachineCode();
-            byte[] authorizeCode = readAuthorizeFile(authorizePath);
-            if (machineCode == null) {
-                logger.error("机器码获取失败. 请检查联系管理员. ");
-                return null;
-            }
-            if(authorizeCode == null || authorizeCode.length == 0) {
-                logger.error("授权文件读取失败. 请检查授权文件是否存在. ");
-                return null;
-            }
             // 使用 base64 转换文本
             byte[] data = Base64Utils.decode(authorizeCode);
             String code = new String(data);
-            logger.info("code: {}", code);
+//            logger.info("code: {}", code);
             // 解密授权文件
-            String password = machineCode.substring(16, 32) + machineCode + machineCode.substring(64, 80);
+            String password = getAuthorizePasswd(machineCode);
             String decryptStr = AesUtils.decrypt(code, password);
-            logger.info("decryptStr: {}", decryptStr);
+//            logger.info("decryptStr: {}", decryptStr);
             return decryptStr;
         }catch (Exception e) {
             logger.error("授权文件解析失败. 请检查练习管理员进行排查. ");
@@ -89,34 +131,40 @@ public class Authorize {
     }
 
     // 生成授权文件
-    public static boolean generateAuthorizeFile(String authorizePath, String authorizeCode) {
+    public static boolean saveAuthorizeFile(String authorizePath, String authorizeJson) {
         try{
             String machineCode = getMachineCode();
             if (machineCode == null) {
                 logger.error("机器码获取失败. 请检查联系管理员. ");
                 return false;
             }
-            if(authorizeCode == null || authorizeCode.length() == 0) {
+            if(authorizeJson == null || authorizeJson.length() == 0) {
                 logger.error("授权码获取失败. 请检查授权码是否正确. ");
                 return false;
             }
             // 机器码长度转换 96 位 到128位 从16位 开始 取 16个字符 添加至机器码前方  再从 64位开始取 16个字符 添加至机器码后方
-            String key = machineCode.substring(16, 32) + machineCode + machineCode.substring(64, 80);
-            logger.info("key: {}", key);
-            logger.info("key length {}", key.length());
+            String key = getAuthorizePasswd(machineCode);
             // 解密授权文件
-            String encryptStr = AesUtils.encrypt(authorizeCode, key);
-            logger.info("encryptStr: {}", encryptStr);
+            String encryptStr = AesUtils.encrypt(authorizeJson, key);
             // 使用 base64 转换文本
             byte[] data = Base64Utils.encode(encryptStr.getBytes());
             String code = new String(data);
-            logger.info("code: {}", code);
-            // 写入文件
+
+            // 授权数据写入文件
             File file = new File(authorizePath);
-            if(!file.exists()) {
-                file.createNewFile();
+            if(file.exists()) {
+                file.delete();
             }
+            file.createNewFile();
             IoUtils.writeTxtFile(file, code);
+
+            // 机器码写入文件
+            File machineFile = new File(baseMachineFilePath);
+            if(machineFile.exists()) {
+                machineFile.delete();
+            }
+            machineFile.createNewFile();
+            IoUtils.writeTxtFile(machineFile, machineCode);
             return true;
         }catch (Exception e) {
             logger.error("授权文件生成失败. 请检查练习管理员进行排查. ");
@@ -126,16 +174,67 @@ public class Authorize {
     }
 
     // 基础授权文件解析
-    public static authorData parseBaseAuthorizeFile(String authorizePath) {
-        String data = decryptAuthorizeFile(authorizePath);
+    public static AuthorData parseBaseAuthorizeFile(String machineCode, String authorizePath) {
+        String data = decryptAuthorizeFile(machineCode, authorizePath);
         if(data == null) {
             return null;
         }
+//        logger.info("data: {}", data);
         // json 解析 fastjson2 依赖
-        JSONObject  = JSON.parse(data);
+        AuthorData authorData = JSON.parseObject(data, AuthorData.class);
+        // 输出解析结果
+        logger.info("机器码: {}", authorData.getMachineCode());
+        logger.info("公司名: {}", authorData.getCompany());
+        logger.info("授权码: {}", authorData.getAuthorizeCode());
+        logger.info("请求授权时间: {}", authorData.getAuthorizeTime());
+//        logger.info("用户密码: {}", authorData.getPassword());
         return authorData;
     }
 
 
+    // 创建授权文件
+    public static boolean generateAuthorizeFile(String authorizePath, String company, String userPassword) {
+        String machineCode = getMachineCode();
+        AuthorData authorData = new AuthorData();
+        if (machineCode == null) {
+            logger.error("机器码获取失败. 请检查联系管理员. ");
+            return false;
+        }
+        if(company == null || company.length() == 0) {
+            logger.error("公司名获取失败. 请检查公司名是否正确. ");
+            return false;
+        }
+        if(userPassword == null || userPassword.length() == 0) {
+            logger.error("用户密码获取失败. 请检查用户密码是否正确. ");
+            return false;
+        }
+        authorData.setMachineCode(machineCode);
+        authorData.setCompany(company);
+        authorData.setPassword(userPassword);
+        // 获取当前时间,使用 ISO8601 格式
+        authorData.setAuthorizeTime(DateUtil.getNowForISO8601());
+        // 构建授权码 md5(机器码 + 公司名 + 授权时间)
+        String authorizeCode = Md5Utils.hash(upCompany + machineCode + company + authorData.getAuthorizeTime());
+        authorData.setAuthorizeCode(authorizeCode);
+        // 转为 json 字符
+        String jsonStr = JSON.toJSONString(authorData);
+        return saveAuthorizeFile(authorizePath, jsonStr);
+    }
+
+    // 读取授权批准文件
+    public static byte[] readAuthorizeApproveFile(String path) {
+        if(path == null) {
+            path = baseAuthorizeFilePath;
+        }
+        logger.info("path: {}", path);
+        File file = new File(path);
+        if(!file.exists()) {
+            logger.error("无法获取到授权批准文件. 请检查授权批准文件是否存在.");
+            return null;
+        }
+        byte[] data = IoUtils.readFileToByte(file);
+        // 解析授权文件
+        return data;
+    }
 
 }

+ 211 - 0
src/main/java/com/genersoft/iot/vmp/conf/AuthorizeApprove.java

@@ -0,0 +1,211 @@
+package com.genersoft.iot.vmp.conf;
+
+import com.alibaba.fastjson2.JSON;
+import com.genersoft.iot.vmp.utils.DateUtil;
+import net.roseboy.classfinal.util.IoUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.util.Base64Utils;
+
+import java.io.File;
+
+public class AuthorizeApprove {
+
+    // 机器码
+    private String machineCode;
+    // 加密后的授权数据
+    private String encryptAuthorData;
+
+    // 请求生成时间
+    private String requestTime;
+
+    // 批准生成时间
+    private String approveTime;
+
+    // 批准人
+    private String approver;
+
+    // 授权天数
+    private int authorizeDay;
+
+    public final static String baseAuthorizeApproveFilePath = "authorize/authorizeApprove.hfy";
+    private final static Logger logger = LoggerFactory.getLogger(Authorize.class);
+    // 读取授权文件
+    private static byte[] readAuthorizeApproveFile(String path) {
+        if(path == null) {
+            path = baseAuthorizeApproveFilePath;
+        }
+        logger.info("path: {}", path);
+        File file = new File(path);
+        if(!file.exists()) {
+            logger.error("无法解析授权请求文件");
+            return null;
+        }
+        byte[] data = IoUtils.readFileToByte(file);
+        // 解析授权文件
+        return data;
+    }
+    public static String getApprovePasswd(AuthorData authorData, String machineCode) {
+        return authorData.getPassword() + machineCode + authorData.getAuthorizeTime();
+    }
+    // 加密并保存授权批准文件
+    public static boolean saveAuthorizeApproveFile(AuthorizeApprove authorizeApprove,AuthorData authorData,  String targetPath) {
+        if (authorizeApprove == null) {
+            logger.error("授权批准文件为空, 无法保存");
+            return false;
+        }
+        if (targetPath == null) {
+            logger.error("请输入授权文件保存路径");
+            return false;
+        }
+        // 生成授权批准文件
+        String approveStr = JSON.toJSONString(authorizeApprove);
+
+        String password = getApprovePasswd(authorData, authorData.getMachineCode());
+        try{
+            // 加密授权文件
+            String encryptStr = AesUtils.encrypt(approveStr, password);
+
+            // 使用 base64 转换文本
+            byte[] approveData = encryptStr.getBytes();
+            byte[] approveByte = Base64Utils.encode(approveData);
+            // 保存授权文件
+            File file = new File(targetPath);
+            if (file.exists()) {
+                file.delete();
+                logger.info("授权批准文件已存在, 正在覆盖");
+            }
+            file.createNewFile();
+            IoUtils.writeTxtFile(file, approveByte.toString());
+            return true;
+        }catch(Exception e)
+        {
+            logger.error("授权批准文件生成失败. 请检查练习管理员进行排查. ");
+            logger.error("错误信息: {}", e.getMessage());
+            return false;
+        }
+    }
+    // 生成授权文件
+    public static AuthorizeApprove generateAuthorizeApprove(String machineCode, String authorizeFilePath, String approver, int p_authorizeDay ) {
+        // 获取密文
+        String encryptAuthorData = Authorize.getEncryptAuthorData(authorizeFilePath);
+        // 读取授权文件
+        AuthorData authorData = Authorize.parseBaseAuthorizeFile(machineCode, authorizeFilePath);
+
+        if (authorData == null) {
+            logger.error("授权文件解析失败,请检查对应文件是否正确");
+            return null;
+        }
+        // 判断机器码是否一致
+        if (!authorData.getMachineCode().equals(machineCode)) {
+            logger.error("授权文件机器码不一致,请检查对应文件是否正确");
+            return null;
+        }
+
+        // 生成授权批准文件
+        AuthorizeApprove authorizeApprove = new AuthorizeApprove();
+        // 机器码
+        authorizeApprove.setMachineCode(machineCode);
+        // 授权请求时间
+        authorizeApprove.setRequestTime(authorData.getAuthorizeTime());
+        // 授权发布时间
+        authorizeApprove.setRequestTime(DateUtil.getNowForISO8601());
+        // 请求密文
+        authorizeApprove.setEncryptAuthorData(encryptAuthorData);
+        // 授权天数
+        authorizeApprove.setAuthorizeDay(p_authorizeDay);
+        // 批准人
+        authorizeApprove.setApprover(approver);
+        return authorizeApprove;
+    }
+
+    /**
+     * 解析授权批准文件
+     * @param machineCode 机器码
+     * @param authorData 授权数据
+     * @return
+     */
+    public static AuthorizeApprove parseAuthorizeApprove (String authorizeApproveFilePath, String machineCode,  AuthorData authorData) {
+        if (authorData == null) {
+            logger.info("授权数据解析失败");
+            return null;
+        }
+        authorizeApproveFilePath = authorizeApproveFilePath == null ? baseAuthorizeApproveFilePath : authorizeApproveFilePath;
+        // 读取授权批准文件
+        byte[] approveByte = readAuthorizeApproveFile(authorizeApproveFilePath);
+        if (approveByte == null) {
+            logger.info("授权批准文件读取失败,请检查对应文件是否正确");
+            return null;
+        }
+        // 解析授权批准文件
+        AuthorizeApprove authorizeApprove = null;
+        // 使用 base64 转换文本
+        byte[] approveData = Base64Utils.decode(approveByte);
+        String code = new String(approveData);
+
+        // 解密授权文件
+        String password = authorData.getPassword() + machineCode;
+        try
+        {
+            String decryptStr = AesUtils.decrypt(code, password);
+            authorizeApprove = JSON.parseObject(decryptStr, AuthorizeApprove.class);
+            return authorizeApprove;
+        }catch(Exception e)
+        {
+            logger.error("授权授权请求文件解析失败. 请检查练习管理员进行排查. ");
+            logger.error("错误信息: {}", e.getMessage());
+            return null;
+        }
+
+
+    }
+
+
+    public String getMachineCode() {
+        return machineCode;
+    }
+
+    public void setMachineCode(String machineCode) {
+        this.machineCode = machineCode;
+    }
+
+    public String getEncryptAuthorData() {
+        return encryptAuthorData;
+    }
+
+    public void setEncryptAuthorData(String encryptAuthorData) {
+        this.encryptAuthorData = encryptAuthorData;
+    }
+
+    public String getRequestTime() {
+        return requestTime;
+    }
+
+    public void setRequestTime(String requestTime) {
+        this.requestTime = requestTime;
+    }
+
+    public String getApproveTime() {
+        return approveTime;
+    }
+
+    public void setApproveTime(String approveTime) {
+        this.approveTime = approveTime;
+    }
+
+    public String getApprover() {
+        return approver;
+    }
+
+    public void setApprover(String approver) {
+        this.approver = approver;
+    }
+
+    public int getAuthorizeDay() {
+        return authorizeDay;
+    }
+
+    public void setAuthorizeDay(int authorizeDay) {
+        this.authorizeDay = authorizeDay;
+    }
+}

+ 8 - 3
src/main/java/com/genersoft/iot/vmp/conf/ServiceInfo.java

@@ -12,7 +12,7 @@ public class ServiceInfo implements ApplicationListener<WebServerInitializedEven
     private final Logger logger = LoggerFactory.getLogger(ServiceInfo.class);
 
     private static int serverPort;
-
+    private static String proPassword;
     public static int getServerPort() {
         return serverPort;
     }
@@ -22,11 +22,16 @@ public class ServiceInfo implements ApplicationListener<WebServerInitializedEven
         // 项目启动获取启动的端口号
         ServiceInfo.serverPort = event.getWebServer().getPort();
         logger.info("项目启动获取启动的端口号:  " + ServiceInfo.serverPort);
-        // 检测是否包含机器码
-
     }
 
     public void setServerPort(int serverPort) {
         ServiceInfo.serverPort = serverPort;
     }
+
+    public static String getProPassword() {
+        return proPassword;
+    }
+    public void setProPassword(String proPassword) {
+        ServiceInfo.proPassword = proPassword;
+    }
 }

+ 3 - 3
src/main/java/com/genersoft/iot/vmp/conf/SpringDocConfig.java

@@ -23,10 +23,10 @@ public class SpringDocConfig {
     @Bean
     public OpenAPI springShopOpenApi() {
         Contact contact = new Contact();
-        contact.setName("pan");
-        contact.setEmail("648540858@qq.com");
+        contact.setName("hfy");
+        contact.setEmail("10086@qq.com");
         return new OpenAPI()
-                .info(new Info().title("WVP-PRO 接口文档")
+                .info(new Info().title("接口文档")
                         .contact(contact)
                         .description("开箱即用的28181协议视频平台")
                         .version("v2.0")

+ 10 - 0
src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java

@@ -60,6 +60,8 @@ public class UserSetting {
 
     private List<String> allowedOrigins = new ArrayList<>();
 
+    private String proPasswd = "";
+
     public Boolean getSavePositionHistory() {
         return savePositionHistory;
     }
@@ -249,4 +251,12 @@ public class UserSetting {
     }
 
 
+    public String getProPasswd() {
+        return proPasswd;
+    }
+
+    public void setProPasswd(String proPasswd) {
+        this.proPasswd = proPasswd;
+    }
+
 }

+ 15 - 3
src/main/java/com/genersoft/iot/vmp/conf/redis/RedisConfig.java

@@ -1,10 +1,15 @@
 package com.genersoft.iot.vmp.conf.redis;
 
 
+import com.genersoft.iot.vmp.VManageBootstrap;
 import com.genersoft.iot.vmp.common.VideoManagerConstants;
 import com.genersoft.iot.vmp.service.redisMsg.*;
+import io.lettuce.core.api.StatefulRedisConnection;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.cache.annotation.CachingConfigurerSupport;
+import org.springframework.context.ConfigurableApplicationContext;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.core.annotation.Order;
@@ -16,6 +21,8 @@ import org.springframework.data.redis.serializer.StringRedisSerializer;
 
 import com.genersoft.iot.vmp.utils.redis.FastJsonRedisSerializer;
 
+import javax.annotation.PreDestroy;
+
 
 /**
  * @description:Redis中间件配置类,使用spring-data-redis集成,自动从application.yml中加载redis配置
@@ -26,7 +33,7 @@ import com.genersoft.iot.vmp.utils.redis.FastJsonRedisSerializer;
 @Configuration
 @Order(value=1)
 public class RedisConfig extends CachingConfigurerSupport {
-
+	private final static Logger logger = LoggerFactory.getLogger(RedisConfig.class);
 	@Autowired
 	private RedisGpsMsgListener redisGPSMsgListener;
 
@@ -47,9 +54,10 @@ public class RedisConfig extends CachingConfigurerSupport {
 
 	@Autowired
 	private RedisPushStreamResponseListener redisPushStreamResponseListener;
-
+	private RedisTemplate _redisTemplate;
 	@Bean
 	public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
+		logger.debug("RedisTemplate");
 		RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
 		// 使用fastJson序列化
 		FastJsonRedisSerializer fastJsonRedisSerializer = new FastJsonRedisSerializer(Object.class);
@@ -61,6 +69,7 @@ public class RedisConfig extends CachingConfigurerSupport {
 		redisTemplate.setKeySerializer(new StringRedisSerializer());
 		redisTemplate.setHashKeySerializer(new StringRedisSerializer());
 		redisTemplate.setConnectionFactory(redisConnectionFactory);
+		_redisTemplate = redisTemplate;
 		return redisTemplate;
 	}
 
@@ -74,7 +83,8 @@ public class RedisConfig extends CachingConfigurerSupport {
 	 */
 	@Bean
 	RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory) {
-
+		// logger.info("RedisMessageListenerContainer");
+		logger.debug("RedisMessageListenerContainer");
         RedisMessageListenerContainer container = new RedisMessageListenerContainer();
         container.setConnectionFactory(connectionFactory);
 		container.addMessageListener(redisGPSMsgListener, new PatternTopic(VideoManagerConstants.VM_MSG_GPS));
@@ -86,4 +96,6 @@ public class RedisConfig extends CachingConfigurerSupport {
 		container.addMessageListener(redisPushStreamResponseListener, new PatternTopic(VideoManagerConstants.VM_MSG_STREAM_PUSH_RESPONSE));
         return container;
     }
+
+
 }

+ 2 - 1
src/main/resources/application.yml

@@ -157,7 +157,8 @@ user-settings:
     logInDatebase: true
     # 使用推流状态作为推流通道状态
     use-pushing-as-status: true
-
+    # 程序密码,用于启动程序
+    pro-passwd: hfypassword
 # 关闭在线文档(生产环境建议关闭)
 springdoc:
     api-docs:

+ 15 - 8
设备绑定机制.md

@@ -2,7 +2,7 @@
 
 ## 操作流程
 1. 用户执行启动脚本
-2. 生成机器码
+2. 生成授权密钥
 3. 用户将机器码发送给管理员
 4. 管理员生成授权信息,以及对应的授权程序
 
@@ -15,7 +15,8 @@
 
 ### 授权文件
 1. 基础授权文件
-> 用于申请授权信息
+> 用于申请授权信息  
+
 - 机器码
 - 服务端时间戳
 - 随机码
@@ -24,11 +25,17 @@
 2. 授权信息文件
 > 用于存储授权信息
 > 由管理员生成
+
 - 机器码
-- 授权码生成时间
-- 程序密码
-- 授权时间 (授权码生成时间 + 有效期)
+- 授权码生成时间 (单位:秒)
+- 随机码
+- 程序密码 
+- 授权有效期 (单位:天)
 
-3. 授权程序
-- 程序运行的时间戳
-- 上次记录生成的时间戳
+3. 程序运行记录文件
+> 用于记录程序运行信息
+> 由程序生成,每小时生成一次
+
+- 机器码
+- 程序运行时间 (单位:秒)
+- 检测时间 (单位:秒)