当前位置: 首页 > news >正文

Unity开发授权系统

Unity开发授权系统

引子

因为有些客户尾款到账不及时,因此研究了一套授权系统,当授权到期后,系统就提示软件授权已到期,不能继续使用云云,这样方便尾款的收回。

大体需求就是
  • 时间相关性,可以自由设置授权到期日期,到达时间后提示过期。
  • 机器相关性,有时候是按照机器来授权的,需要识别不同的机器,分别给客户授权。

思路和需要的技术点

  • 提取机器特征码,可以参考的思路是:CPU序列号、硬盘序列号、主板序列号、网卡MAC地址等。其中,获取MAC地址最简单,但是也最不稳定,客户网络环境如果比较复杂,比如多张网卡,比如拔插网线可能就会导致网卡状态变化,读取时就会有问题。其余的,相对好一点,推荐几个序列号都读取一下,然后拼接使用。但也不是百分百稳定,毕竟各种厂商设备型号繁杂。问题的关键在于如何获取这些序列号,网络上搜寻的解决方案,全都是使用System.Management,然而,这个其实并不能直接在unity中使用。即便是将Unity InstallPath/Editor/Data/MonoBleedingEdge/lib/mono/2.0-api/System.Management.dll文件引入Unity工程,也会报“未实现”的错。所以最终,我的解决方案是写了一个额外的控制台程序,在这个控制台程序中读取硬件信息,然后输出,在Unity中调用这个控制台程序,在后台去获取硬件信息。这就又引发了一系列其他的问题,比如:假设客户知道了原理,如果他伪造一个读取硬件信息的程序,当我unity去调用时,他就可以返回给我假的硬件特征码,比如无论什么机器都返回一个固定的值,这样他就可以只用一台机器的授权,好几台机器共用了。所以,我Unity在调用之前,必须判断好这个读取硬件特征码的软件,是我的软件,而不是他伪造的。还有一个问题,在unity中,调用的时候,必须是后台调用,不能出现任何界面。
    那么两个问题的解决方法,就是:
    1. 在调用外部进程之前,首先创建一个内存映射文件(MemoryMappedFile,它虽然叫做File,但其实它只需要在内存中,实际并不需要磁盘IO),这个内存映射文件,是可以跨进程共享数据的。读硬件特征码的程序,读到硬件信息后,加密后写到这个内容映射文件中,而不是在控制台输出,这样,这个读取硬件特征的软件,客户就很难替换,因为:①客户不知道内存映射文件对象的名称;②客户不知道加密方式,或者说即便知道加密方式,不知道加密的key,无法向内存映射文件中写如正确数值。这样就避免了客户自行替换读硬件信息的程序。
      提取特征码的具体算法,网络上很多,这里不再赘述。
    2. 在unity中静静的运行一个后台进程,其实很容易,这里以获取控制台输出为例:
// 读取机器码的协程
private static IEnumerator ReadMachineCode()
{// 启动读取硬件特征码的进程string exePath = Path.Combine(Application.streamingAssetsPath, "MachineCode/GetMachineCode.exe");if (!File.Exists(exePath)){OnMachineCodeReaded?.Invoke(null);yield break;}Process process = new Process();process.StartInfo.FileName = exePath;process.StartInfo.Arguments = "Your Some Arguments"; // 据实际情况写process.StartInfo.UseShellExecute = false;process.StartInfo.CreateNoWindow = true;process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;process.StartInfo.WorkingDirectory = Path.Combine(Application.streamingAssetsPath, "MachineCode");process.StartInfo.RedirectStandardOutput = true;process.Start();// 等待进程结束while (!process.HasExited)yield return null;// 获取进程运行结果,以控制台为例,而不是内存文件映射,生产环境应读取内存文件映射中的结果string result = process.StandardOutput.ReadToEnd();OnMachineCodeReaded?.Invoke(result);
}
  • 构建授权数据,本质上是构架一个数据体,用于描述授权文件的信息。然后转换为Json字符串,方便加密和存储。
[Serializable]
internal class MachineLicense
{public string code;  // 目标机器码public string desc;  // 说明public int year;     // 授权到期年public int month;    // 授权到期月public int day;      // 授权到期日
}
[Serializable]
internal class LicenseData
{public string projectName;  // 项目名称public string description;	// 说明public string check;        // 校验字符串public List<MachineLicense> data;  // 授权数据
}
  • AES加密原理,采用AES加密。这也是很成熟的加密算法,下面提供一些与加解密相关的封装好的方法:
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;public static class AESCryptography
{// AES加密public static byte[] Encrypt(byte[] rgbKey, byte[] rgbIV, string sourceText){using MemoryStream memoryStream = new MemoryStream();using (Aes aes = Aes.Create())using (ICryptoTransform transform = aes.CreateEncryptor(rgbKey, rgbIV))using (CryptoStream cryptoStream = new CryptoStream(memoryStream, transform, CryptoStreamMode.Write))using (StreamWriter streamWriter = new StreamWriter(cryptoStream)){streamWriter.Write(sourceText);streamWriter.Flush();}return memoryStream.ToArray();}// AES解密public static string Decrypt(byte[] rgbKey, byte[] rgbIV, byte[] cipherBuffer){using MemoryStream stream = new MemoryStream(cipherBuffer);using Aes aes = Aes.Create();using ICryptoTransform transform = aes.CreateDecryptor(rgbKey, rgbIV);using CryptoStream cryptoStream = new CryptoStream(stream, transform, CryptoStreamMode.Read);using StreamReader streamReader = new StreamReader(cryptoStream);return streamReader.ReadToEnd();}// 字符串MD5加密public static byte[] Md5Encrypt(string tex){var md5 = MD5.Create();return md5.ComputeHash(Encoding.UTF8.GetBytes(tex));}// 将byte[]数据输出为HEX字符串public static string ByteArrayToString(byte [] data){StringBuilder sb = new StringBuilder();int index = 0;foreach( var d in data ){if (index > 0 && index % 4 == 0)sb.Append('-');sb.Append(d.ToString("X2"));++index;}return sb.ToString();}// 将HEX字符串转换为byte[16]public static bool HexStringToByte16(string hex, out byte[] data){data = new byte[16];int index = 0;bool half = true;foreach (var ch in hex){byte d;switch (ch){case >= '0' and <= '9':d = (byte)(ch - '0');break;case >= 'A' and <= 'F':d = (byte)(10 + (ch - 'A'));break;case >= 'a' and <= 'f':d = (byte)(10 + (ch - 'a'));break;case ' ':case '-':case ':':continue;default:return false;}if (half)data[index] = (byte) (d << 4);else{data[index] = (byte) ( data[index] | d );++index;if (index > 15)break;}half = !half;}return true;}
}
  • 制作授权文件,Unity端判定授权无效,或授权到期后,系统会停止工作,并将机器码显示到屏幕上,提示授权到期信息等。我方技术人员获取到机器码后,按照上述算法制作授权文件,经过AES加密,生成Base64字符串,保存到授权文件中,交付客户。
  • 授权验证,客户将授权文件存放到指定路径后,Unity端验证过程:首先读取授权文件,并进行解密,转换为解密后的json字符串,再转换为LicneseData数据,如果校验码等信息全部通过后,再判定当前设备机器码是否在授权文件中,并且授权日期是否到期。完成授权验证。
foreach (var date in from target in licenseData.data where string.CompareOrdinal(target.code, MachineCode) == 0 select new DateTime(target.year, target.month, target.day).AddDays(1))
{OnLicenseChecked?.Invoke(DateTime.Now < date);yield break;
}
OnLicenseChecked?.Invoke(false);

相关文章:

Unity开发授权系统

Unity开发授权系统 引子 因为有些客户尾款到账不及时&#xff0c;因此研究了一套授权系统&#xff0c;当授权到期后&#xff0c;系统就提示软件授权已到期&#xff0c;不能继续使用云云&#xff0c;这样方便尾款的收回。 大体需求就是 时间相关性&#xff0c;可以自由设置授…...

一周时间,开发了一款封面图生成工具

介绍 这是一款封面图的制作工具&#xff0c;根据简单的配置即可生成一张好看的封面图&#xff0c;目前已有七款主题可以选择。做这个工具的初衷来自平时写文章&#xff0c;都为封面图发愁&#xff0c;去图片 网站上搜索很难找到满意的&#xff0c;而且当你要的图如果要搭配上文…...

【.NET Core】深入理解异步编程模型(APM)

【.NET Core】深入理解异步编程模型&#xff08;APM&#xff09; 文章目录 【.NET Core】深入理解异步编程模型&#xff08;APM&#xff09;一、APM概述二、IAsyncResult接口2.1 BeginInvoke2.2 EndInvoke2.3 IAsyncResult属性2.4 IAsyncResult异步演示 三、通过结束异步操作来…...

pyqtgraph绘图类

pyqtgraph绘图类 pyqtgraph绘图有四种方法: 方法描述pyqtgraph.plot()创建一个新的QWindow用来绘制数据PlotWidget.plot()在已存在的QWidget上绘制数据PlotItem.plot()在已存在的QWidget上绘制数据GraphicsLayout.addPlot()在网格布局中添加一个绘图 上面四个方法都接收同样…...

C#6-10新增的内容

目录 异常筛选器 属性语法 表达式主体定义 Null 条件运算符 ?. 和 ?[] 使用 $ 的字符串内插 nameof 表达式 元组类型 模糊匹配 本地函数 Expression-bodied 成员 Reference 变量 ?、??和??= .. 模式匹配功能(C# 9) Record init c#8.NET Framework 4.8…...

【立创EDA-PCB设计基础】3.网络表概念解读+板框绘制

前言&#xff1a;本文对网络表概念解读板框绘制&#xff08;确定PCB板子轮廓&#xff09; 网络表概念解读 在本专栏的上一篇文章【嘉立创EDA-PCB设计指南】2&#xff0c;将设计的原理图转为了PCB&#xff0c;在PCB界面下出现了所有的封装&#xff0c;以及所有的飞线属性&…...

在Python环境中运行R语言的配环境实用教程

前情提要 在做一些生物信息与医学统计的工作&#xff0c;本来偷懒希望只靠python完成的&#xff0c;结果还是需要用R语言&#xff0c;倒腾了一会儿&#xff0c;调成功了&#xff0c;就记录一下这个过程。 我的环境&#xff1a; win10, pycharm, R-4.3.2 首先&#xff0c;我们…...

2023年总结我所经历的技术大变革

&#x1f4e2;欢迎点赞 &#xff1a;&#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff0c;赐人玫瑰&#xff0c;手留余香&#xff01;&#x1f4e2;本文作者&#xff1a;由webmote 原创&#x1f4e2;作者格言&#xff1a;新的征程&#xff0c;我们面对的不仅…...

基于YOLOv7算法的高精度实时车载摄像头下车辆检测系统(PyTorch+Pyside6+YOLOv7)

摘要&#xff1a;基于YOLOv7算法的高精度实时车载摄像头下车辆检测系统可用于日常生活中检测与定位车辆&#xff0c;此系统可完成对输入图片、视频、文件夹以及摄像头方式的目标检测与识别&#xff0c;同时本系统还支持检测结果可视化与导出。本系统采用YOLOv7目标检测算法来训…...

深度学习(3)--递归神经网络(RNN)和词向量模型Word2Vec

目录 一.递归神经网络基础概念 二.自然语言处理-词向量模型Word2Vec 2.1.词向量模型 2.2.常用模型对比 2.3.负采样方案 2.4.词向量训练过程 一.递归神经网络基础概念 递归神经网络(Recursive Neural Network, RNN)可以解决有时间序列的问题&#xff0c;处理诸如树、图这样…...

【江科大】STM32:中断系统(理论)

文章目录 中断系统为什么要使用中断中断优先级中断嵌套STM32的中断系统如何管理这些中断NVIC的结构![请添加图片描述](https://img-blog.csdnimg.cn/c77b038fd63a4ddfbcd3b86f6dfe596b.png) 优先级窗口看门狗&#xff08;WWDG&#xff09;&#xff1a;外部中断模块的特性&#…...

JAVA 学习 面试(六)数据类型与方法

数据类型 基本数据类型 为什么float3.4报错 3.4 默认是浮点double类型的&#xff0c;如果赋值给float是向下转型&#xff0c;会出现精度缺失&#xff0c;&#xff0c;需要强制转换 Switch支持的数据类型&#xff1f; byte、short、int、char 、 enum 、 String 基本类型与包…...

Java 一个数组集合List<People> 赋值给另一个数组集合List<NewPeople> ,两个数组集合属性部分一致。

Java 一个数组集合List 赋值给另一个数组集合List &#xff0c;两个数组集合属性部分一致。 下面是一个Demo, 具体要根据自己的业务调整。 import java.util.ArrayList; import java.util.List;class People {private String name;private int age;private String address;publ…...

基于神经网络的电力系统的负荷预测

一、背景介绍&#xff1a; 电力系统负荷预测是生产部门的重要工作之一&#xff0c;通过准确的负荷预测&#xff0c;可以经济合理地安排机组的启停、减少旋转备用容量、合理安排检修计划、降低发电成本和提高经济效益。负荷预测按预测的时间可以分为长期、中期和短期负荷预测。…...

OpenCV第 1 课 计算机视觉和 OpenCV 介绍

文章目录 第 1 课 计算机视觉和 OpenCV 介绍1.机器是如何“看”的2.机器视觉技术的常见应用3.图像识别介绍4. 图像识别技术的常见应用5.OpenCV 介绍6.图像在计算机中的存储形式 第 1 课 计算机视觉和 OpenCV 介绍 1.机器是如何“看”的 我们人类可以通过眼睛看到五颜六色的世界…...

C++面试:stl的栈和队列介绍

目录 栈 栈&#xff08;stack&#xff09;的声明&#xff1a; push()&#xff1a; 将元素推入栈顶 pop()&#xff1a; 弹出栈顶元素 top()&#xff1a; 访问栈顶元素&#xff0c;但不弹出 empty()&#xff1a; 检查栈是否为空 size()&#xff1a; 返回栈中元素的数量 …...

从0开始学习C++ 第十二课:指针强化

第十二课&#xff1a;指针强化 学习目标&#xff1a; 理解常量指针与指针常量的区别。学习如何使用函数指针。掌握指针与数组的高级使用技巧。 学习内容&#xff1a; 常量指针与指针常量 概念&#xff1a; 常量指针是一个指向常量的指针&#xff0c;这意味着不能通过这个指针…...

mongodb和python交互

1. mongdb和python交互的模块 pymongo 提供了mongdb和python交互的所有方法 安装方式: pip install pymongo 2. 使用pymongo 2.1 导入pymongo并选择要操作的集合 数据库和集合能够自动创建 2.1.1 无需权限认证的方式创建连接对象以及集合操作对象 from pymongo import Mong…...

力扣279. 完全平方数

动态规划 思路&#xff1a; 假设 dp[i] 为最少组成数 i 的平方数个数&#xff1b;则其上一个状态为 dp[i - j^2] 1&#xff0c;1 为 j^2&#xff1a; 即 i 的最少完全平方数 i - j^2 的最少完全平方数 1&#xff0c;其中 j^2 < i 为最接近 i 的平方数&#xff1b;初始值…...

【C++】list容器功能模拟实现

介绍 上一次介绍了list队容器的迭代器模拟&#xff0c;这次模拟实现list的简单功能&#xff0c;尤其要注意构造函数、析构函数、以及赋值运算符重载的实现。 list容器需要接纳所有类型的数据&#xff0c;因此&#xff0c;结构设置与迭代器设置同理&#xff0c;需要引入结点&…...

在软件开发中正确使用MySQL日期时间类型的深度解析

在日常软件开发场景中&#xff0c;时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志&#xff0c;到供应链系统的物流节点时间戳&#xff0c;时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库&#xff0c;其日期时间类型的…...

《从零掌握MIPI CSI-2: 协议精解与FPGA摄像头开发实战》-- CSI-2 协议详细解析 (一)

CSI-2 协议详细解析 (一&#xff09; 1. CSI-2层定义&#xff08;CSI-2 Layer Definitions&#xff09; 分层结构 &#xff1a;CSI-2协议分为6层&#xff1a; 物理层&#xff08;PHY Layer&#xff09; &#xff1a; 定义电气特性、时钟机制和传输介质&#xff08;导线&#…...

TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案

一、TRS收益互换的本质与业务逻辑 &#xff08;一&#xff09;概念解析 TRS&#xff08;Total Return Swap&#xff09;收益互换是一种金融衍生工具&#xff0c;指交易双方约定在未来一定期限内&#xff0c;基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...

select、poll、epoll 与 Reactor 模式

在高并发网络编程领域&#xff0c;高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表&#xff0c;以及基于它们实现的 Reactor 模式&#xff0c;为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。​ 一、I…...

10-Oracle 23 ai Vector Search 概述和参数

一、Oracle AI Vector Search 概述 企业和个人都在尝试各种AI&#xff0c;使用客户端或是内部自己搭建集成大模型的终端&#xff0c;加速与大型语言模型&#xff08;LLM&#xff09;的结合&#xff0c;同时使用检索增强生成&#xff08;Retrieval Augmented Generation &#…...

Linux 内存管理实战精讲:核心原理与面试常考点全解析

Linux 内存管理实战精讲&#xff1a;核心原理与面试常考点全解析 Linux 内核内存管理是系统设计中最复杂但也最核心的模块之一。它不仅支撑着虚拟内存机制、物理内存分配、进程隔离与资源复用&#xff0c;还直接决定系统运行的性能与稳定性。无论你是嵌入式开发者、内核调试工…...

使用LangGraph和LangSmith构建多智能体人工智能系统

现在&#xff0c;通过组合几个较小的子智能体来创建一个强大的人工智能智能体正成为一种趋势。但这也带来了一些挑战&#xff0c;比如减少幻觉、管理对话流程、在测试期间留意智能体的工作方式、允许人工介入以及评估其性能。你需要进行大量的反复试验。 在这篇博客〔原作者&a…...

【Redis】笔记|第8节|大厂高并发缓存架构实战与优化

缓存架构 代码结构 代码详情 功能点&#xff1a; 多级缓存&#xff0c;先查本地缓存&#xff0c;再查Redis&#xff0c;最后才查数据库热点数据重建逻辑使用分布式锁&#xff0c;二次查询更新缓存采用读写锁提升性能采用Redis的发布订阅机制通知所有实例更新本地缓存适用读多…...

Python Einops库:深度学习中的张量操作革命

Einops&#xff08;爱因斯坦操作库&#xff09;就像给张量操作戴上了一副"语义眼镜"——让你用人类能理解的方式告诉计算机如何操作多维数组。这个基于爱因斯坦求和约定的库&#xff0c;用类似自然语言的表达式替代了晦涩的API调用&#xff0c;彻底改变了深度学习工程…...

掌握 HTTP 请求:理解 cURL GET 语法

cURL 是一个强大的命令行工具&#xff0c;用于发送 HTTP 请求和与 Web 服务器交互。在 Web 开发和测试中&#xff0c;cURL 经常用于发送 GET 请求来获取服务器资源。本文将详细介绍 cURL GET 请求的语法和使用方法。 一、cURL 基本概念 cURL 是 "Client URL" 的缩写…...