springboot整合License授权控制

yml配置文件设置读取licenses文件位置 

license:filePath: "D://licenses.lc"

 创建licenses文件码


import sun.misc.BASE64Encoder;import java.security.MessageDigest;
import java.text.SimpleDateFormat;
import java.util.Date;/*** 许可文件的生成类<br>* 只用于在公司内网生成许可文件,不得出公司内网、更不得打包到项目中* @author lidaquan**/
public class LicenseMaker {private static final String TYPE_DATE = "date";private static final String TYPE_DATE_DW = "date_hw";private static final String OS_WINDOWS = "Windows";private static final String OS_LINUX = "Linux";private static final String OS_AIX = "AIX";private static final String FAKE_MAC = "abcdef123456";/**** @param type* @param endDay* @param osArray 如果macAddressArray不为空,则osArray与macAddressArray的个数必须相同* @param macAddressArray 单实例环境与单机集群环境均为一个,多机集群环境为多个;不管什么环境,对于每台机器应该只允许一个;出于保护目的,目前最多允许4个;如果不是基于硬件的许可,可以设为null* @param serie 从技术上控制可以使用该许可的项目类别(可以达到强制控制的目的,但无法细化到具体项目或用户)* @param user  从字面上声明可以使用该许可的项目名称或用户名称(无法达到强制控制的目的,但可以细化到具体项目或用户)*/public static void create(String type, String endDay, String[] osArray, String[] macAddressArray, String serie, String user){String osSet = "";String macAddressSet = "";if(type == null || "".equals(type) || endDay == null || "".equals(endDay) || osArray == null || osArray.length == 0 || serie == null || "".equals(serie) || user == null || "".equals(user)){throw new IllegalArgumentException("参数不能为空");}else if(TYPE_DATE_DW.equals(type)){
//            if(macAddressArray == null || macAddressArray.length == 0){
//                throw new IllegalArgumentException("参数不能为空");
//            }
//            if(macAddressArray.length > 4){
//                throw new IllegalArgumentException("参数超过上限");
//            }
//            if(osArray.length != macAddressArray.length){
//                throw new IllegalArgumentException("osArray与macAddressArray的数量不一致");
//            }for(int i = 0, size = osArray.length;i < size;i++){String os = osArray[i];if(os == null || "".equals(os)){throw new IllegalArgumentException("参数不能为空");}
//                String macAddress = macAddressArray[i];
//                if(macAddress == null || "".equals(macAddress) || macAddress.length() != 12){
//                    throw new IllegalArgumentException("参数不能为空并且长度必须为12位");
//                }osSet += os;
//                macAddressSet += macAddress;if(i < size - 1){osSet += "_";
//                    macAddressSet += "_";}}}else if(TYPE_DATE.equals(type)){if(osArray.length > 1){throw new IllegalArgumentException("参数超过上限");}osSet = osArray[0];}try{SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");Date endDate = dateFormat.parse(endDay);Date now = new Date();Date authDate = new Date(now.getYear(), now.getMonth(), now.getDate());System.out.println("许可颁发类型:" + type);System.out.println("许可结束日期:" + dateFormat.format(endDate));System.out.println("许可颁发日期:" + dateFormat.format(authDate));System.out.println("许可适用系统:" + osSet);System.out.println("许可颁发网卡:" + macAddressSet);System.out.println("许可颁发产品:" + serie);System.out.println("许可颁发用户:" + user);System.out.println("---------------------------------------------------------------");MessageDigest md = MessageDigest.getInstance("SHA-1");System.out.print("serial=");System.out.print(encode(type));md.update(type.getBytes());byte[] degist = md.digest();System.out.print("-" + new BASE64Encoder().encode(degist));String endDateStr = dateFormat.format(endDate);System.out.print("-" + encode(endDateStr));md.update(endDateStr.getBytes());degist = md.digest();System.out.print("-" + new BASE64Encoder().encode(degist));String authDateStr = dateFormat.format(authDate);System.out.print("-" + encode(authDateStr));md.update(authDateStr.getBytes());degist = md.digest();System.out.print("-" + new BASE64Encoder().encode(degist));System.out.print("-" + encode(osSet));md.update(osSet.getBytes());degist = md.digest();System.out.print("-" + new BASE64Encoder().encode(degist));if(TYPE_DATE.equals(type)){macAddressSet = FAKE_MAC;}else{macAddressSet = macAddressSet.toLowerCase();}System.out.print("-" + encode(macAddressSet));md.update(macAddressSet.getBytes());degist = md.digest();System.out.print("-" + new BASE64Encoder().encode(degist));System.out.print("-" + encode(serie));md.update(serie.getBytes());degist = md.digest();System.out.print("-" + new BASE64Encoder().encode(degist));System.out.print("-" + encode(user));md.update(user.getBytes());degist = md.digest();System.out.print("-" + new BASE64Encoder().encode(degist));}catch(Exception e){e.printStackTrace();}}private static String encode(String msg){byte[] code = msg.getBytes();exchangeCode(code);BASE64Encoder encoder = new BASE64Encoder();return encoder.encode(code);}private static void exchangeCode(byte[] code){int i, iSize;iSize = code.length/8;for (i = 0;i < iSize;i++){exchange(code, i*8 + 7, i*8);exchange(code, i*8 + 5, i*8 + 2);}}private static void exchange(byte[] code, int i, int j){byte temp = code[i];code[i] = code[j];code[j] = temp;}public static void main(String[] args){create(TYPE_DATE_DW, "2025-02-04", new String[]{OS_LINUX, OS_WINDOWS}, new String[]{}, "appName", "appChineseName");}}

/*** ${appName}的许可标识<br>* 只允许用于${appName}的项目**/
public class LicenseChecker_appName extends LicenseChecker {public static final String SERIE = "appName";@Overrideprotected String getSerie() {return SERIE;}}

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;import java.net.NetworkInterface;
import java.security.MessageDigest;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Enumeration;/*** 许可文件的校验类<br>* 随同许可文件打包到项目中** @author bo a bo*/
public abstract class LicenseChecker {public boolean check() {boolean valid = false;try {String serial = ReadLicenseUtils.readLicense();if (StringUtil.isEmpty(serial)) {throw new RuntimeException();// 未读取到license}MessageDigest md = MessageDigest.getInstance("SHA-1");String type = decode(serial.split("-")[0]);md.update(type.getBytes());String degistStr = new BASE64Encoder().encode(md.digest());if (!serial.split("-")[1].equals(degistStr)) {throw new RuntimeException();//许可颁发类型的序列号摘要不对}String endDateStr = decode(serial.split("-")[2]);md.update(endDateStr.getBytes());degistStr = new BASE64Encoder().encode(md.digest());if (!serial.split("-")[3].equals(degistStr)) {throw new RuntimeException();//许可结束日期的序列号摘要不对}String authDateStr = decode(serial.split("-")[4]);md.update(authDateStr.getBytes());degistStr = new BASE64Encoder().encode(md.digest());if (!serial.split("-")[5].equals(degistStr)) {throw new RuntimeException();//许可颁发日期的序列号摘要不对}String osSet = decode(serial.split("-")[6]);md.update(osSet.getBytes());degistStr = new BASE64Encoder().encode(md.digest());if (!serial.split("-")[7].equals(degistStr)) {throw new RuntimeException();//许可适用系统的序列号摘要不对}String hwSet = decode(serial.split("-")[8]);md.update(hwSet.getBytes());degistStr = new BASE64Encoder().encode(md.digest());if (!serial.split("-")[9].equals(degistStr)) {throw new RuntimeException();//许可颁发网卡的序列号摘要不对}String serie = decode(serial.split("-")[10]);md.update(serie.getBytes());degistStr = new BASE64Encoder().encode(md.digest());if (!serial.split("-")[11].equals(degistStr)) {throw new RuntimeException();//许可颁发产品的序列号摘要不对}String user = decode(serial.split("-")[12]);md.update(user.getBytes());degistStr = new BASE64Encoder().encode(md.digest());if (!serial.split("-")[13].equals(degistStr)) {throw new RuntimeException();//许可颁发用户的序列号摘要不对}SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");Date endDate = dateFormat.parse(endDateStr);Date authDate = dateFormat.parse(authDateStr);Date now = new Date();Date today = new Date(now.getYear(), now.getMonth(), now.getDate());if (endDate.compareTo(today) >= 0 && authDate.compareTo(today) <= 0 && this.getSerie().equals(serie)) {if ("date".equals(type) && System.getProperty("os.name").startsWith(osSet)) {valid = true;}/*else if("devel".equals(user)){//这个分支用于方便开发人员在本地进行开发“绑定硬件的许可类型”的项目;只在项目工程的 WEB-INF\lib\ 目录下使用,在SVN上一定要注释掉(避免此分支出现在非本地开发环境)!!!valid = true;}*/ else {String[] osArray = osSet.split("_");if (!StringUtil.isEmpty(hwSet)) {String[] hwArray = hwSet.split("_");Enumeration<NetworkInterface> niel = NetworkInterface.getNetworkInterfaces();allNetworkInterface:while (niel.hasMoreElements()) {NetworkInterface ni = niel.nextElement();byte[] mac = ni.getHardwareAddress();if (mac == null || mac.length != 6) {continue;}StringBuffer macBuffer = new StringBuffer();for (int i = 0, size = mac.length; i < size; i++) {String s = "0" + Integer.toHexString(mac[i]);s = s.substring(s.length() - 2);macBuffer.append(s);}for (int i = 0; i < hwArray.length; i++) {String hw = hwArray[i];String os = osArray[i];if (macBuffer.toString().equals(hw) && System.getProperty("os.name").startsWith(os)) {valid = true;break allNetworkInterface;}}}} else {for (int i = 0; i < osArray.length; i++) {String os = osArray[i];if (System.getProperty("os.name").startsWith(os)) {valid = true;break;}}}}}} catch (Exception e) {}return valid;}protected abstract String getSerie();private static String decode(String dec) {try {BASE64Decoder decoder = new BASE64Decoder();byte[] code = decoder.decodeBuffer(dec);vexchangeCode(code);return new String(code);} catch (Exception ex) {ex.printStackTrace();return null;}}private static void vexchangeCode(byte[] code) {int i, iSize;iSize = code.length / 8;for (i = 0; i < iSize; i++) {exchange(code, i * 8 + 2, i * 8 + 5);exchange(code, i * 8, i * 8 + 7);}}private static void exchange(byte[] code, int i, int j) {byte temp = code[i];code[i] = code[j];code[j] = temp;}}

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;import java.util.List;/*** @author bo a bo*/
@Data
@Component
@ConfigurationProperties(value = "license")
public class LicenseProperties {private String filePath;private String value;/*** 是否开启全局拦截,默认开启*/private Boolean enabled = Boolean.TRUE;/*** 当不开启全局拦截时,需要配置哪些url需要拦截*/private List<String> urlList;}

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.nio.charset.StandardCharsets;
import java.util.Properties;public class ReadLicenseUtils {private static final String licenseFile = "licenses.lc";//在AIX7.1中,文件名必须加后缀,否则无法读取public static String readLicense() {LicenseProperties licenseProperties = null;try {licenseProperties = SpringUtil.getBean(LicenseProperties.class);} catch (Exception e) {licenseProperties = new LicenseProperties();}String filePath = licenseProperties.getFilePath();String license = null;if (FileUtil.exist(filePath)) {// 当配置的文件存在时,读取文件中的licensetry {license = FileUtil.readLine(new RandomAccessFile(filePath, "r"), StandardCharsets.UTF_8);} catch (FileNotFoundException e) {throw new RuntimeException(e);}}if (StrUtil.isNotBlank(license)) {return license;}// 当文件不存在,获取读取内容为空时,使用配置中的licesnelicense = licenseProperties.getValue();if (StrUtil.isNotBlank(license)) {return license;}
//        license = ResourceUtil.readStr(licenseFile, StandardCharsets.UTF_8);
//        if (StrUtil.isNotBlank(license)) {
//            return license;
//        }
//        license = ResourceUtil.readStr("/" + licenseFile, StandardCharsets.UTF_8);
//        if (StrUtil.isNotBlank(license)) {
//            return license;
//        }
//        return null;// 当配置中的license为空时,读取resources中的licenses.lc文件中的licenseInputStream is = null;try {Properties prop = new Properties();ClassLoader classLoader = ReadLicenseUtils.class.getClassLoader();is = classLoader.getResourceAsStream("/" + licenseFile);//某些JDK、中间件要加“/”if (is == null || is.available() == 0) {is = classLoader.getResourceAsStream(licenseFile);//某些JDK、中间件不加“/”}prop.load(is);String serial = prop.getProperty("serial");return serial;} catch (Exception e) {} finally {if (is != null) {try {is.close();} catch (Exception e) {}}}return null;}}
/*** 字符串工具类* @author bo a bo**/
public class StringUtil {/*** 字符串是否为空(null、空串、空格、"null")* @param s* @return*/public static boolean isEmpty(String s){if(s == null || "".equals(s.trim()) || "null".equalsIgnoreCase(s.trim())){return true;}return false;}}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/475949.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【代码随想录】贪心

455. 分发饼干 题目 随想录 本质&#xff1a; 对于每个孩子&#xff0c;使用可以满足该孩子的最小的饼干。所以对孩子胃口和饼干进行sort排序&#xff0c;依次将大的饼干满足给孩子。 贪心策略&#xff1a; 想一下局部最优&#xff0c;想一下全局最优&#xff0c;如果局部最优…

QWen2.5学习

配置环境 pip install transformers 记得更新一下&#xff1a;typing_extensions pip install --upgrade typing_extensions 安装modelscope modelscope/modelscope: ModelScope: bring the notion of Model-as-a-Service to life. 下载这个仓库的代码上传到服务器解压 推…

存算分离的过去、现在和未来

存算分离架构&#xff0c;作为数据处理领域的一个重要概念&#xff0c;从其最初的雏形到如今广泛应用&#xff0c;经历了多次迭代和变革。雁飞老师在分享中从过去的存算架构&#xff0c;逐步讲述存算分离的演进&#xff0c;现今的存算分离架构的优势及其在 Databend 中的体现&a…

web——upload-labs——第九关——特殊字符::$DATA绕过

特殊字符::$DATA绕过 典型绕过场景 在一些系统中&#xff0c;::$DATA 被用于绕过文件路径的限制。比如&#xff1a; 路径过滤绕过&#xff1a;如果系统有某种机制来检查和限制文件路径&#xff08;例如&#xff0c;禁止访问某些系统目录或敏感文件&#xff09;&#xff0c;通…

图的存储、遍历以及Dijkstra/Floyd/Kruskal/Prim/拓扑排序/关键路径(实验8--作业)

图–数据结构操作与算法全解析 一、引言 图作为一种重要的数据结构&#xff0c;在计算机科学与众多领域中都有着广泛的应用。它能够有效地描述和解决各种复杂的关系问题&#xff0c;如网络拓扑、路径规划、资源分配等。本文将详细介绍图的相关操作和知识点&#xff0c;包括图…

利用Vue的相关特性,制作相册

目录 一、整体结构 1、设置一个div盒子 2、设置图片展示 3、页码按钮 4、翻页按钮 二、CSS样式 1、 .clear_ele::after 2、设置图片、按钮等属性的样式 三、JavaScript部分&#xff08;Vue&#xff09; 1、导入模块 2、创建Vue应用 ①定义响应式数据 ②定义事件处…

优化表单交互:在 el-select 组件中嵌入表格显示选项

介绍了一种通过 el-select 插槽实现表格样式数据展示的方案&#xff0c;可更直观地辅助用户选择。支持列配置、行数据绑定及自定义搜索&#xff0c;简洁高效&#xff0c;适用于复杂选择场景。完整代码见GitHub 仓库。 背景 在进行业务开发选择订单时&#xff0c;如果单纯的根…

(C语言)文件操作

目录 文件 程序文件 数据文件 文件名 ​编辑数据文件的分类 文件的打开和关闭 流 标准流 1&#xff09;stdin 2&#xff09;stdout 3&#xff09;stderr 文件指针 文件的打开和关闭 对文件内容操作的函数 1&#xff09;fgetc&#xff0c;fputc 2&#xff09;fp…

AI修改验证账号名正则表达式的案例

我有如下的一行老代码&#xff0c;今天复用的时候发现当时注释写错了&#xff0c;改好以后请AI再检查一遍。 因为这次AI的分析的思路很典范&#xff0c;所以拿出来分享一下。 提问&#xff1a; 请看一下这个正则和后面的注释是否匹配&#xff0c;现在的验证规则是否保证账号至…

SQL进阶技巧:如何进行数字范围统计?| 货场剩余货位的统计查询方法

目录 0 场景描述 1 剩余空位区间和剩余空位编号统计分析 2 查找已用货位区间 3 小结 0 场景描述 这是在做一个大型货场租赁系统时遇到的问题&#xff0c;在计算货场剩余存储空间时&#xff0c;不仅仅需要知道哪些货位是空闲的&#xff0c;还要能够判断出哪些货位之间是连…

彻底理解如何保证Redis和数据库数据一致性问题

一.背景 系统中缓存最常用的策略是&#xff1a;服务端需要同时维护 DB 和 Cache 并且是以 DB 的结果为准&#xff0c;那么就可能出现 DB 和 Cache 数据不一致的问题。 二.读数据 逻辑如下&#xff1a; 当客户端发起查询数据的请求&#xff0c;首先回去Redis中查看没有没该数据&…

后仿真中的SDF语法之关键字 IOPATH 用法详解

在后仿真中&#xff0c;SDF&#xff08;Standard Delay Format&#xff09;文件用于描述设计的时序信息&#xff0c;而IOPATH是SDF中的一个关键结构&#xff0c;用于定义单元间的路径延迟。以下是IOPATH关键字的用法及其相关内容的详细介绍&#xff1a; IOPATH结构旨在将延迟数…

Springboot 整合 Java DL4J 搭建智能问答系统

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家&#xff0c;历代文学网&#xff08;PC端可以访问&#xff1a;https://literature.sinhy.com/#/literature?__c1000&#xff0c;移动端可微信小程序搜索“历代文学”&#xff09;总架构师&#xff0c;15年工作经验&#xff0c;…

基于SpringBoot的“网上书城管理系统”的设计与实现(源码+数据库+文档+PPT)

基于SpringBoot的“网上书城管理系统”的设计与实现&#xff08;源码数据库文档PPT) 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBoot 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 系统功能结构图 系统首页界面图 用户注册界面…

测评部署和管理 WordPress 最方便的面板

新版宝塔面板快速搭建WordPress新手教程 - 倚栏听风-Morii - 博客园 初学者使用1Panel面板快速搭建WordPress网站 - 倚栏听风-Morii - 博客园 可以看到&#xff0c;无论是宝塔还是1Panel&#xff0c;部署和管理WordPress都有些繁琐&#xff0c;而且还需要额外去配置Nginx和M…

网络安全问题概述

1.1.计算机网络面临的安全性威胁 计算机网络上的通信面临以下的四种威胁&#xff1a; (1) 截获——从网络上窃听他人的通信内容。 (2) 中断——有意中断他人在网络上的通信。 (3) 篡改——故意篡改网络上传送的报文。可应用于域名重定向&#xff0c;即钓鱼网站。 (4) 伪造——伪…

视觉顶会论文 | 基于Swin Transformer的轴承故障诊断

往期精彩内容&#xff1a; Python-凯斯西储大学&#xff08;CWRU&#xff09;轴承数据解读与分类处理 Pytorch-LSTM轴承故障一维信号分类(一)-CSDN博客 Pytorch-CNN轴承故障一维信号分类(二)-CSDN博客 Pytorch-Transformer轴承故障一维信号分类(三)-CSDN博客 三十多个开源…

Altenergy电力系统控制软件 status_zigbee SQL注入漏洞复现(CVE-2024-11305)

0x01 产品简介 Altenergy电力系统控制软件是Altenergy Power System推出的一款专业软件。旨在为用户提供全面、高效、安全的电力系统控制解决方案。广泛应用于各类电力系统领域,如电力调度中心、发电厂、变电站、工业园区等。通过该软件的应用,用户可以实现对电力系统的全面…

java: spire.pdf.free 9.12.3 create pdf

可以用windows 系统中文字体&#xff0c;也可以从文件夹的字体文件 /*** encoding: utf-8* 版权所有 2024 ©涂聚文有限公司* 许可信息查看&#xff1a;言語成了邀功盡責的功臣&#xff0c;還需要行爲每日來值班嗎* 描述&#xff1a;* # Author : geovindu,Geovin Du 涂…

AUTOSAR网络管理中的主动唤醒与被动唤醒

文章目录 1、主动/被动唤醒源、主动/被动唤醒节点2、网络拓扑说明 1、主动/被动唤醒源、主动/被动唤醒节点 休眠唤醒需要有一个触发源来进行触发&#xff0c;我们常用的NM报文是其中的载体之一。休眠唤醒的触发源又分为主动唤醒源和被动唤醒源。 主动唤醒源&#xff0c;就是能…