我打算开发一款应用激活系统

我打算开发一款应用激活系统


目前整个 LicenseServer 商业授权系统 的规划进度如下:

章节 内容 状态
第一部分 整体架构设计与技术选型 ✅ 完成
第二部分 安全模型与授权体系设计 ✅ 完成
第三部分 部署架构设计(Docker/Kubernetes/云部署) ✅ 完成
第四部分 数据库详细设计 ✅ 完成
第五部分 安全增强设计 ✅ 完成
第六部分 项目工程规范、CI/CD、开发流程 ✅ 完成
第七部分 高级安全体系(密钥、签名、防破解等) ✅ 完成
第八部分(一) 数据库与后端核心代码 ✅ 完成
第八部分(二) Identity + JWT + Refresh Token认证系统 ✅ 完成
第八部分(三) License核心业务实现 ✅ 完成
第八部分(四) 客户端SDK实现 ✅ 完成
第八部分(五) 生产级安全加固 ✅ 完成
第八部分(六) 支付系统 + 自动发货 + 商业闭环 ✅ 完成
第八部分(七) Admin Console管理后台 ⬅️ 当前开始
第八部分(八) 完整部署上线方案 待完成
第八部分(九) 客户端商业化加固与发布流程 待完成
第八部分(十) 最终源码目录、Docker部署文件、生产配置 待完成

你描述的系统本质上是一个商业软件 License(许可证)管理平台,类似于:

  • JetBrains License Server
  • Microsoft Product Activation
  • Adobe Licensing
  • Paddle / Lemon Squeezy + 自建 License Server
  • Cryptlex、Keygen.sh 等商业授权系统

它不是简单的“生成激活码”,而是一个包含:

  1. 订单绑定
  2. 用户身份管理
  3. License 生成
  4. 设备指纹绑定
  5. 激活验证
  6. 离线授权(可选)
  7. 防破解、防爆破
  8. 后台权限控制
  9. 审计日志

的完整系统。

根据你的技术背景(你熟悉 C#、Node.js、PostgreSQL、Docker、CI/CD,也考虑 Web3/AI 全栈方向),我建议不要用传统 PHP,而采用现代云原生架构。

推荐技术栈(商业级方案)

我个人推荐:

后端:Go / C# ASP.NET Core

数据库:PostgreSQL

管理后台:Next.js + TypeScript

客户端 SDK:C++ / Rust / C#

部署:Docker + Kubernetes(后期)


方案一(我最推荐):Go + PostgreSQL + Next.js

架构:

                用户
                 |
                 |
          License Website
          Next.js + Tailwind
                 |
                 |
          API Gateway
                 |
              Go API
                 |
        ----------------
        |              |
   PostgreSQL       Redis
        |
 License Database

后端

Go

推荐:

  • Gin
  • Fiber
  • Echo

原因:

1. 非常适合 License Server

授权服务器特点:

  • 请求量不一定巨大
  • 但是安全要求高
  • 高并发验证
  • 低延迟

Go非常适合。

例如:

用户打开软件:

软件
 |
 | license_key
 |
 v

https://api.xxx.com/activate


返回:

{
 status:"success",
 expire:"2027-08-01",
 device_limit:3,
 signature:"xxxx"
}

Go处理非常舒服。

2. 编译成单文件

例如:

license-server

部署:

docker run license-server

简单。


方案二:C# ASP.NET Core(其实也非常适合你)

你的背景有 .NET,所以:

ASP.NET Core 9
+
Entity Framework Core
+
PostgreSQL
+
Identity

也是优秀方案。

优点:

  • 企业级安全成熟
  • JWT
  • OAuth
  • RBAC权限
  • 加密库成熟
  • Windows生态强

如果你的软件客户端也是:

  • Windows
  • .NET
  • WPF
  • WinUI

那么我甚至更推荐 C#。

架构:

ASP.NET Core API

       |
       |
 PostgreSQL

       |
 Identity Server

       |
 Admin Panel

前端管理后台

推荐:

Next.js

原因:

你的激活系统一定需要:

  • 用户中心
  • 登录
  • 找回 License
  • 订单查询
  • 设备管理
  • 管理员后台

技术:

Next.js 16
+
TypeScript
+
Tailwind CSS
+
shadcn/ui

页面:

用户:

/login

/register

/licenses

/devices


管理员:

/admin/users

/admin/licenses

/admin/logs

数据库设计

核心表:

users

用户:

id
email
password_hash
created_at

licenses

激活码:

id

license_key_hash

product_id

max_devices

expire_date

status

created_at

注意:

不要保存明文:

不要:

48D0-61CD-35FE...

保存:

SHA256(
48D0-61CD...
)

数据库里面:

a91fc92b88a7...

即使数据库泄露:

攻击者拿不到激活码。


devices

设备绑定:

id

license_id

device_hash

device_name

os

first_activate

last_check

例如:

电脑生成:

CPU ID
+
Motherboard UUID
+
Disk serial

然后:

SHA256:

A82B9F883...

服务器只保存:

设备指纹Hash

激活流程设计

第一次激活

用户输入:

License:

48D0-61CD-35FE-9C9B

Email:

test@gmail.com

客户端生成:

device_id

发送:

POST /activate


{
 license:
 "xxxx",

 device:
 "a82f92..."
}

服务器:

检查:

License存在?



是否超过设备数量?



绑定设备



生成授权Token

返回:

{
license_status:"active",

token:
"eyxxxx",

signature:
"xxxx"

}

防破解核心:不要返回明文授权信息

错误方式:

返回:

{
"user":"Tom",
"expire":"2027",
"max_device":3
}

别人抓包修改即可。


正确:

使用:

非对称加密

服务器:

私钥:

private.key

客户端:

公钥:

public.key

服务器:

签名:

license data

+

RSA/ECDSA signature

客户端:

验证:

public key



signature verify

即使破解客户端:

没有服务器私钥:

无法生成新License。

推荐:

ECDSA P-256

或者

Ed25519

不要用 RSA 2048 新项目。


防爆破设计

1. License不要顺序生成

不要:

000001
000002
000003

应该:

随机:

48D0-61CD-35FE-9C9B-5358-3725-D644-1A18

128bit以上随机。


2. 激活接口限流

例如:

Redis:

IP:

一分钟最多10次


License:

一分钟最多5次

使用:

  • Redis Rate Limit
  • Cloudflare WAF

3. 登录保护

必须:

  • Argon2id密码Hash
  • MFA
  • 登录失败锁定

密码:

不要:

bcrypt

推荐:

Argon2id

防止内部人员查看License

你提出的这个非常重要。

比如:

管理员:

SELECT * FROM licenses

看到:

48D0-61CD...

这是风险。

方案:

数据库加密存储

保存:

license_hash

+

encrypted_license

例如:

license:

AES-256-GCM

加密

密钥:

不要放数据库。

使用:

  • Hashicorp Vault
  • AWS KMS
  • Azure Key Vault

结构:

Database

encrypted_license


        |

        |

Vault

master key

权限设计

RBAC:

角色:

super_admin

license_admin

support

readonly

客服:

只能:

查询邮箱

重置设备

不能:

查看License原文

客户端保护

如果你的软件:

Windows

推荐:

C++

或者:

C# + Native DLL

不要:

纯 .NET EXE

因为容易:

  • ILSpy
  • dnSpy

方案:

Main.exe

+

License.dll(C++)

关键验证:

放Native。


推荐最终架构

如果我是设计商业产品:

                    Cloudflare

                        |

                    Nginx


                        |

                 Next.js Website

                        |

                 ASP.NET Core / Go

                        |

        --------------------------------

        PostgreSQL        Redis


                        |

                  Vault/KMS


                        |

                License SDK


             Windows/Mac/Linux

语言选择排序(针对你的情况)

排名 技术 推荐
1 C# ASP.NET Core ★★★★★
2 Go ★★★★★
3 Rust ★★★★
4 Node.js NestJS ★★★★
5 Java Spring Boot ★★★
6 PHP Laravel ★★

结合你的背景:

  • 已经会 .NET
  • 做过全栈
  • 熟悉 Docker
  • 熟悉 PostgreSQL

我建议:

第一版:

ASP.NET Core 9
+
PostgreSQL
+
Redis
+
Next.js
+
Docker

第二版:

加入:

Vault
+
KMS
+
客户端SDK
+
离线License

这个技术路线可以做到接近商业授权系统的安全等级。你后续如果开发的是 Windows 桌面软件(尤其 WinUI/WPF/.NET),C# 生态会更加顺手。

非常好,这一步其实比前面的设计更重要。

前面的文档解决的是系统怎么设计,但是一个商业项目真正开始开发时,最大的问题通常是:

  • Mac、Windows、Linux环境不一致
  • Node/npm版本混乱
  • 数据库版本不同导致迁移失败
  • Docker环境差异
  • 前端依赖锁定问题
  • CI/CD和本地开发不一致

所以我建议单独建立一份:

LicenseServer 商业授权系统

多平台开发与生产部署规范文档 v1.0

目标:

在 macOS、Windows、Linux 三个平台拥有完全一致的开发体验。


第一章:总体技术路线选择

最终推荐架构:

Frontend
    |
    |
Next.js + TypeScript
    |
    |
ASP.NET Core 10 Web API
    |
    |
PostgreSQL
    |
    |
Redis
    |
    |
Docker

客户端:

Windows
    |
C# / Avalonia / WPF

macOS
    |
.NET + Native

Linux
    |
.NET

第二章:开发环境统一原则

核心原则

不要依赖:

  • 系统Node
  • 系统Python
  • 系统数据库
  • 系统.NET

全部版本固定。

采用:

mise
+
Docker
+
Dev Container

第三章:开发工具版本建议

1. Git

所有平台:

Git >= 2.45

检查:

git --version

2. VS Code

推荐:

VS Code Stable

插件统一:

C# Dev Kit

ESLint

Prettier

Docker

PostgreSQL

GitLens

Tailwind CSS IntelliSense

3. mise版本管理

我建议你继续使用 mise。

原因:

你之前已经使用过:

  • Go
  • Flutter
  • Python

mise 非常适合多语言项目。

安装:

mac/Linux:

curl https://mise.run | sh

Windows:

PowerShell:

winget install jdx.mise

第四章:统一语言版本

一、C# / .NET

推荐:

.NET 10 LTS

原因:

你的项目:

  • 商业授权服务器
  • 长期维护
  • 企业软件

不要追最新preview。

安装:

检查:

dotnet --version

项目:

global.json

{
 "sdk":
 {
   "version":
   "10.0.100",
   
   "rollForward":
   "latestPatch"
 }
}

作用:

所有机器:

Mac:

10.0.100

Windows:

10.0.100

Linux:

10.0.100

二、Node.js

这里重点回答你的问题:

Node.js 能不能换 Bun?

答案:

开发环境可以,商业项目核心构建不建议完全替代。

原因:

Bun现在非常优秀:

优势:

  • 安装快
  • JS运行速度快
  • 自带bundler
  • 自带test

但是:

大型商业项目:

尤其:

  • Next.js
  • Prisma
  • Tailwind
  • shadcn
  • 企业CI

Node兼容性仍然最好。

我的建议:

推荐方案

开发:

Bun

可以。

生产:

Node.js LTS

CI:

Node.js LTS

也就是说:

开发机器

Mac:
bun


Windows:
bun


Linux:
bun



CI/CD:

node


Production:

node

三、Bun版本

固定:

bun 1.2+

使用:

bun --version

项目:

.bun-version

1.2.20

第五章:TypeScript版本建议

你问:

TypeScript 7.0怎么样?

TypeScript 7.0 已经进入新的原生编译器路线,官方目标是提升编译速度和降低内存使用,采用新的原生实现。

但是商业项目需要考虑生态兼容。

我的建议:

2026新项目:

可以使用:

TypeScript 7.x

但是:

需要锁版本。

例如:

package.json:

{
 "devDependencies":
 {
   "typescript":
   "7.0.2"
 }
}

不要:

^7.0.0

避免自动升级。


第六章:Next.js版本

推荐:

Next.js 16

原因:

你的项目:

Admin Console

官网

用户中心

推荐:

Next.js
+
React
+
TypeScript
+
Tailwind
+
shadcn/ui

package:

{
"dependencies":
{
"next":
"16.x",

"react":
"19.x"
}
}

第七章:数据库版本选择

这是商业系统最关键。

PostgreSQL

推荐:

PostgreSQL 17

原因:

成熟:

  • JSON性能好
  • 索引优秀
  • 长期支持

不要使用:

latest

Docker:

postgres:17

不要:

postgres:latest

第八章:ORM选择

.NET:

推荐:

Entity Framework Core

版本:

EF Core 10

原因:

官方生态。


数据库迁移:

统一:

dotnet ef migrations add Initial

第九章:Redis版本

推荐:

Redis 7.4 LTS

用途:

  • Session
  • Cache
  • Rate limit
  • License查询缓存

Docker:

redis:7.4

第十章:消息队列

第一版:

不要复杂化。

不用:

Kafka

推荐:

Redis Queue

或者:

RabbitMQ

版本:

RabbitMQ 4.x

以后:

百万用户:

Kafka。


第十一章:搜索系统

第一版:

PostgreSQL全文搜索。

不要马上:

ElasticSearch。

原因:

增加:

  • 内存
  • 运维
  • 安全

第十二章:完整开发环境

最终:

Developer Machine


macOS

Windows

Linux


        |

        |

mise


        |

        |

Docker


        |

        |

PostgreSQL

Redis

Mailhog


        |

        |

ASP.NET Core


        |

        |

Next.js

第十三章:项目根目录配置

最终:

LicenseServer/


├── .mise.toml

├── global.json

├── docker-compose.dev.yml

├── package.json

├── bun.lock

├── Directory.Build.props


├── backend/


├── frontend/


├── client/


└── docs/

第十四章:mise配置

.mise.toml

[tools]

dotnet="10.0"

node="24"

bun="1.2"

python="3.13"

go="1.25"

所有开发者:

执行:

mise install

自动安装。


第十五章:Docker开发环境

docker-compose.dev.yml

services:


postgres:

 image:
 postgres:17


 environment:

  POSTGRES_PASSWORD:
   password


 ports:

  - 5432:5432



redis:

 image:
 redis:7.4


 ports:

  - 6379:6379

启动:

docker compose -f docker-compose.dev.yml up -d

第十六章:邮件测试

不要开发阶段发真实邮件。

使用:

Mailhog

Docker:

mailhog:

 image:
 mailhog/mailhog


ports:

- 8025:8025

浏览:

localhost:8025

第十七章:跨平台注意事项

路径

不要:

C:\project

代码:

使用:

/

换行符

Git:

配置:

git config --global core.autocrlf false

统一:

LF。


文件权限

Linux:

注意:

chmod

Docker:

不要root运行。


第十八章:IDE统一

推荐:

全部:

VS Code。

原因:

Mac:

Windows:

Linux:


第十九章:生产服务器版本

推荐:

Ubuntu Server 24.04 LTS


Docker 29.x


PostgreSQL 17


Redis 7.4


Nginx 1.26+

.NET 10

第二十章:最终推荐技术栈

Backend

组件 版本
.NET 10 LTS
ASP.NET Core 10
EF Core 10
PostgreSQL 17
Redis 7.4
Serilog 最新版稳定版

Frontend

组件 版本
Next.js 16
React 19
TypeScript 7.0.x
Tailwind 4
shadcn/ui latest

Runtime

环境 版本
Node 24 LTS
Bun 1.2
Docker 29
Git 2.45+

第二十一章:我的最终建议

针对你的情况(Mac + PC + Linux,多系统开发,并且目标是商业软件):

我建议:

Backend:

C# .NET 10 LTS


Frontend:

Next.js 16

TypeScript 7


Package:

Bun开发

Node生产


Database:

PostgreSQL 17


Cache:

Redis 7.4


Environment:

mise


Deployment:

Docker Compose


CI:

GitHub Actions

这是目前比较稳,同时又保持现代化的方案。


下一部分我建议继续写:

第九部分:从零开始创建 LicenseServer 实际开发教程

内容:

  1. 创建 Git 仓库
  2. 初始化 .NET Solution
  3. 创建 Clean Architecture
  4. 配置 PostgreSQL + EF Core
  5. 创建 User / License Entity
  6. 第一个 API
  7. Docker 开发环境启动
  8. Mac/Windows/Linux 三端验证流程

这一部分会开始进入真正编码阶段。

好的

LicenseServer 商业授权系统开发实战文档 v1.0

第九部分:从零开始创建 LicenseServer 实际开发教程

第一阶段:项目初始化与基础架构搭建

目标:

完成:

✅ Git仓库 ✅ 多平台开发环境 ✅ .NET Solution ✅ Clean Architecture ✅ PostgreSQL ✅ EF Core ✅ Docker开发环境 ✅ 第一个API接口

开发环境支持:

  • macOS(Intel / Apple Silicon)
  • Windows 10/11
  • Linux(Ubuntu/Debian/Arch)

1. 创建项目目录

统一目录:

例如:

mac/Linux:

mkdir LicenseServer

cd LicenseServer

Windows PowerShell:

mkdir LicenseServer

cd LicenseServer

最终:

LicenseServer/

作为项目根目录。


2. 初始化Git仓库

执行:

git init

创建:

.gitignore

.NET模板:

dotnet new gitignore

追加:

# Node
node_modules/

.next/

dist/


# Environment

.env

.env.*


# Docker

postgres-data/


# IDE

.vscode/


# OS

.DS_Store

Thumbs.db

3. 初始化项目文档

创建:

docs/

结构:

docs/

├── architecture.md

├── database.md

├── api.md

├── deployment.md

└── security.md

4. 创建.NET Solution

进入根目录:

dotnet new sln \
-n LicenseServer

生成:

LicenseServer.sln

5. 创建后端目录

创建:

mkdir backend

进入:

cd backend

6. 创建Clean Architecture

最终结构:

backend/

├── LicenseServer.API

├── LicenseServer.Application

├── LicenseServer.Domain

├── LicenseServer.Infrastructure

└── LicenseServer.Tests

7. 创建Domain项目

dotnet new classlib \
-n LicenseServer.Domain

移动:

mv LicenseServer.Domain ../

8. 创建Application项目

dotnet new classlib \
-n LicenseServer.Application

9. 创建Infrastructure项目

dotnet new classlib \
-n LicenseServer.Infrastructure

10. 创建API项目

dotnet new webapi \
-n LicenseServer.API

11. 创建测试项目

dotnet new xunit \
-n LicenseServer.Tests

12. 添加项目到Solution

返回根目录:

cd ..

执行:

dotnet sln add \
backend/*/*.csproj

检查:

dotnet sln list

应该看到:

LicenseServer.API

LicenseServer.Application

LicenseServer.Domain

LicenseServer.Infrastructure

LicenseServer.Tests

13. 建立项目引用关系

架构:

API



Application



Domain


Infrastructure



Application

执行:

Application引用Domain

dotnet add \
backend/LicenseServer.Application \
reference \
backend/LicenseServer.Domain

Infrastructure引用Domain

dotnet add \
backend/LicenseServer.Infrastructure \
reference \
backend/LicenseServer.Domain

Infrastructure引用Application

dotnet add \
backend/LicenseServer.Infrastructure \
reference \
backend/LicenseServer.Application

API引用Application

dotnet add \
backend/LicenseServer.API \
reference \
backend/LicenseServer.Application

API引用Infrastructure

dotnet add \
backend/LicenseServer.API \
reference \
backend/LicenseServer.Infrastructure

14. 安装Entity Framework Core

进入:

cd backend/LicenseServer.Infrastructure

安装:

dotnet add package \
Microsoft.EntityFrameworkCore

PostgreSQL驱动:

dotnet add package \
Npgsql.EntityFrameworkCore.PostgreSQL

迁移工具:

dotnet add package \
Microsoft.EntityFrameworkCore.Design

15. 安装配置管理

API:

cd ../LicenseServer.API

安装:

dotnet add package \
Microsoft.Extensions.Configuration.Json

16. 创建Domain实体

进入:

LicenseServer.Domain

创建:

Entities/

结构:

Entities

├── User.cs

├── License.cs

├── Device.cs

└── Product.cs

17. User实体

User.cs

namespace LicenseServer.Domain.Entities;


public class User
{

public Guid Id {get;set;}


public string Email {get;set;} = "";


public string PasswordHash {get;set;}="";


public DateTime CreatedAt {get;set;}
= DateTime.UtcNow;


}

18. License实体

License.cs

namespace LicenseServer.Domain.Entities;


public class License
{


public Guid Id {get;set;}


public Guid UserId {get;set;}


public string KeyHash {get;set;}="";


public int MaxDevices {get;set;}


public DateTime ExpireAt {get;set;}


public bool Active {get;set;}


public User User {get;set;}=null!;


}

19. 创建数据库Context

Infrastructure:

创建:

Database/

LicenseDbContext.cs

代码:

using Microsoft.EntityFrameworkCore;
using LicenseServer.Domain.Entities;


namespace LicenseServer.Infrastructure.Database;


public class LicenseDbContext
    : DbContext
{


public LicenseDbContext(
DbContextOptions options)
:base(options)
{

}


public DbSet<User> Users => Set<User>();


public DbSet<License> Licenses => Set<License>();


}

20. 配置API连接数据库

Program.cs

添加:

builder.Services
.AddDbContext<LicenseDbContext>(options =>
{

options.UseNpgsql(
builder.Configuration
.GetConnectionString("Default"));

});

21. appsettings.json

API:

添加:

{
"ConnectionStrings":
{

"Default":

"Host=localhost;Database=license;Username=license;Password=password"

}

}

22. 创建Docker开发数据库

根目录:

创建:

docker-compose.dev.yml

内容:

services:


 postgres:


  image:
   postgres:17


  container_name:
   license-postgres-dev


  environment:


   POSTGRES_DB:
    license


   POSTGRES_USER:
    license


   POSTGRES_PASSWORD:
    password



  ports:


   - "5432:5432"



  volumes:


   - postgres-data:/var/lib/postgresql/data



 redis:


  image:
   redis:7.4


  container_name:
   license-redis-dev


  ports:


   - "6379:6379"



volumes:


 postgres-data:

23. 启动开发数据库

根目录:

docker compose \
-f docker-compose.dev.yml \
up -d

检查:

docker ps

应该看到:

license-postgres-dev

license-redis-dev

24. 创建第一次Migration

进入API:

cd backend/LicenseServer.API

执行:

dotnet ef migrations add InitialCreate \
-p ../LicenseServer.Infrastructure \
-s .

25. 更新数据库

dotnet ef database update \
-p ../LicenseServer.Infrastructure \
-s .

成功:

数据库:

license

 ├── Users

 ├── Licenses

 └── __EFMigrationsHistory

26. 创建第一个测试API

API:

创建:

Controllers/TestController.cs

代码:

using Microsoft.AspNetCore.Mvc;


namespace LicenseServer.API.Controllers;


[ApiController]

[Route("api/test")]

public class TestController
:ControllerBase

{


[HttpGet]

public IActionResult Get()
{

return Ok(new
{

message="License Server Running",

time=DateTime.UtcNow

});

}


}

27. 启动API

dotnet run

访问:

https://localhost:7000/api/test

返回:

{
"message":
"License Server Running",

"time":
"2026-xx-xx"
}

28. 三平台验证

macOS

dotnet --version

docker --version

git --version

Windows

PowerShell:

dotnet --version

docker version

git --version

Linux

dotnet --version

docker version

git --version

结果必须一致。


29. 当前阶段完成

现在已经拥有:

模块 状态
Git仓库
Solution结构
Clean Architecture
Domain模型
EF Core
PostgreSQL
Docker开发环境
第一个API

下一阶段:

第九部分(二):实现用户系统 Identity + JWT + Refresh Token

将开始编写真正商业系统核心:

包括:

  1. ASP.NET Core Identity设计
  2. 用户注册
  3. 邮箱验证
  4. BCrypt密码哈希
  5. JWT Access Token
  6. Refresh Token
  7. Token轮换机制
  8. 登录设备管理
  9. MFA设计
  10. 权限RBAC基础

这一部分完成后,你的 LicenseServer 将拥有真正可用的用户认证系统。

LicenseServer 商业授权系统开发实战文档 v1.0

第九部分(二):用户系统 Identity + JWT + Refresh Token 实现

本阶段开始实现真正商业系统基础能力:

目标:

完成:

✅ 用户注册 ✅ 邮箱账户体系 ✅ 密码安全存储 ✅ 登录认证 ✅ JWT Access Token ✅ Refresh Token ✅ Token轮换 ✅ 登录设备管理 ✅ RBAC权限基础 ✅ 后续MFA扩展接口


一、认证系统整体架构

最终流程:

用户


 |

注册


 |

Email验证


 |

Password Hash


 |

PostgreSQL


 |


登录


 |

验证密码


 |

生成:

Access Token

+

Refresh Token


 |

客户端保存


 |

访问API


 |

JWT Middleware验证

二、认证技术选型

采用:

功能 技术
用户管理 ASP.NET Core Identity
密码哈希 PBKDF2
Token JWT
Refresh Token 数据库存储
权限 RBAC
邮箱验证 SMTP
MFA TOTP

三、安装Identity依赖

进入:

cd backend/LicenseServer.Infrastructure

安装:

dotnet add package Microsoft.AspNetCore.Identity.EntityFrameworkCore

JWT:

API项目:

cd ../LicenseServer.API

安装:

dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer

四、修改User实体设计

之前:

User
{
Id
Email
PasswordHash
}

商业版本:

增加:

User


Id

Email

PasswordHash


EmailConfirmed


Status


CreatedAt


LastLoginAt

五、创建ApplicationUser

Domain:

创建:

Entities/ApplicationUser.cs

代码:

using Microsoft.AspNetCore.Identity;


namespace LicenseServer.Domain.Entities;


public class ApplicationUser 
    : IdentityUser<Guid>
{


public DateTime CreatedAt 
{get;set;}
= DateTime.UtcNow;


public DateTime?
LastLoginAt
{get;set;}


public bool IsActive
{get;set;}
=true;


}

六、修改DbContext

替换:

LicenseDbContext

代码:

using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;


public class LicenseDbContext
:
IdentityDbContext<
ApplicationUser,
IdentityRole<Guid>,
Guid>
{


public LicenseDbContext(
DbContextOptions options)
:base(options)
{

}



public DbSet<License>
Licenses
=>Set<License>();


}

七、Identity数据库结构

迁移后:

自动生成:

AspNetUsers

AspNetRoles

AspNetUserRoles

AspNetUserClaims

AspNetUserTokens


Licenses

Devices

八、配置Identity

Program.cs:

添加:

builder.Services
.AddIdentity<
ApplicationUser,
IdentityRole<Guid>
>(options =>
{


options.Password.RequiredLength=12;


options.Password.RequireDigit=true;


options.Password.RequireUppercase=true;


options.Password.RequireLowercase=true;


options.Password.RequireNonAlphanumeric=true;



options.User.RequireUniqueEmail=true;


})

.AddEntityFrameworkStores<LicenseDbContext>();

九、密码安全策略

商业软件建议:

最低:

12字符

大小写

数字

特殊字符

禁止:

123456

password

qwerty

十、JWT配置

appsettings.json:

{
"Jwt":
{

"Key":
"CHANGE_THIS_SECRET_KEY",

"Issuer":
"LicenseServer",

"Audience":
"LicenseClient",

"ExpireMinutes":
15

}

}

十一、JWT Service

Application:

创建:

Interfaces/IJwtService.cs

代码:

public interface IJwtService
{


string GenerateAccessToken(
ApplicationUser user);


string GenerateRefreshToken();


}

十二、JWT实现

Infrastructure:

创建:

Security/JwtService.cs

代码:

using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Security.Cryptography;
using Microsoft.IdentityModel.Tokens;


public class JwtService
:IJwtService
{


private readonly IConfiguration _config;



public JwtService(
IConfiguration config)
{

_config=config;

}



public string GenerateAccessToken(
ApplicationUser user)
{


var claims=new[]
{

new Claim(
JwtRegisteredClaimNames.Sub,
user.Id.ToString()),


new Claim(
JwtRegisteredClaimNames.Email,
user.Email!)

};


var key=new SymmetricSecurityKey(

Encoding.UTF8.GetBytes(
_config["Jwt:Key"]!)

);


var token=new JwtSecurityToken(

issuer:_config["Jwt:Issuer"],

audience:_config["Jwt:Audience"],

claims:claims,

expires:
DateTime.UtcNow.AddMinutes(15),

signingCredentials:
new SigningCredentials(
key,
SecurityAlgorithms.HmacSha256)

);


return new JwtSecurityTokenHandler()
.WriteToken(token);


}



public string GenerateRefreshToken()
{

return Convert.ToBase64String(
RandomNumberGenerator.GetBytes(64));

}


}

十三、Refresh Token数据库设计

创建:

RefreshToken.cs

代码:

public class RefreshToken
{


public Guid Id {get;set;}


public Guid UserId {get;set;}


public string TokenHash {get;set;}="";


public DateTime ExpireAt {get;set;}


public bool Revoked {get;set;}



public ApplicationUser User
{get;set;}=null!;


}

十四、为什么数据库保存Hash?

错误:

数据库

refresh_token=abc123

数据库泄露:

攻击者直接登录。

正确:

保存:

Token:

abc123


SHA256:

91AFxxxxx

数据库只有Hash。


十五、Token生成流程

登录:

用户名密码




验证Identity




生成Access Token




生成Refresh Token




Hash Refresh Token




保存数据库




返回客户端

十六、注册API

Controller:

Controllers/AuthController.cs

接口:

POST

/api/auth/register

请求:

{
"email":
"user@test.com",

"password":
"Password@12345"

}

十七、注册逻辑

伪代码:

var user=new ApplicationUser
{

Email=request.Email,

UserName=request.Email

};


var result=
await userManager
.CreateAsync(
user,
password);


if(result.Succeeded)
{

sendVerifyEmail();

}

十八、登录API

接口:

POST

/api/auth/login

请求:

{
"email":
"user@test.com",

"password":
"Password@12345"

}

返回:

{
"accessToken":
"xxxxx",

"refreshToken":
"xxxxx",

"expires":
900

}

十九、JWT Middleware

Program.cs:

增加:

builder.Services
.AddAuthentication()
.AddJwtBearer(options =>
{


options.TokenValidationParameters
=new TokenValidationParameters
{

ValidateIssuer=true,

ValidateAudience=true,

ValidateLifetime=true,


};

});

启用:

app.UseAuthentication();

app.UseAuthorization();

二十、测试保护API

例如:

[Authorize]

[HttpGet]

public IActionResult Profile()
{

return Ok();

}

没有Token:

返回:

401 Unauthorized

二十一、Refresh Token接口

接口:

POST

/api/auth/refresh

流程:

旧Refresh Token




验证Hash




撤销旧Token




生成新Token




返回

二十二、Token轮换机制

禁止:

一个Refresh Token永久有效。

推荐:

Refresh Token:

30天


Access Token:

15分钟

每次刷新:

旧Token:

Revoked=true

生成:

新Token。


二十三、登录设备管理

增加:

UserDevice.cs

字段:

Id

UserId

DeviceName

OS

IP

LastActive

CreatedAt

用途:

以后:

License设备限制。


二十四、RBAC权限基础

角色:

User

Admin

Support

Finance

SuperAdmin

Identity已经支持。


创建:

await roleManager
.CreateAsync(
new IdentityRole<Guid>
("Admin"));

二十五、Admin权限验证

Controller:

[Authorize(
Roles="Admin"
)]

public IActionResult Users()

{

}

二十六、安全增强

生产必须增加:

登录限流

例如:

5分钟:

失败5次



锁定15分钟

密码泄露检测

建议:

接入:

HaveIBeenPwned API


邮箱验证

注册:

状态:

EmailConfirmed=false

未验证:

不能购买License。


二十七、本阶段完成

功能 状态
ASP.NET Identity
用户注册
密码安全
JWT认证
Refresh Token
Token轮换
设备记录基础
RBAC基础
MFA接口预留

当前系统进度

已经完成:

数据库

Clean Architecture

Identity

JWT认证

下一阶段进入核心商业逻辑:

第九部分(三):License Engine 核心实现

将实现:

  1. License Key生成算法
  2. 48D0-61CD-35FE格式生成
  3. 密钥安全存储
  4. RSA/ECDSA数字签名
  5. 激活API
  6. 设备指纹绑定
  7. 1台/3台/5台限制
  8. 在线Heartbeat
  9. License续期
  10. 禁用与恢复
  11. 防爆破设计

这一部分完成后,你的软件就具备真正的“商业激活系统核心”。

LicenseServer 商业授权系统开发实战文档 v1.0

第九部分(三):License Engine 核心实现

本阶段开始实现整个系统最核心的商业能力:

License生成、签名、激活、设备绑定、授权验证。

完成后,你将拥有类似:

  • JetBrains License
  • Adobe Activation
  • Microsoft Product Activation

这类商业授权体系的核心能力。


一、License Engine设计目标

需要解决:

1. License生成

例如:

用户购买:

Professional 版本
3台设备
365天

生成:

48D0-61CD-35FE-9C9B-5358-3725-D644-1A18

2. 防伪

不能:

客户端:

if(key=="xxx")
{
    unlock();
}

必须:

服务器:

生成:

License Payload

+

Digital Signature

客户端:

验证:

Signature

3. 设备限制

支持:

例如:

Basic:

1台设备

Professional:

3台设备

Enterprise:

5台/无限设备

4. 防爆破

攻击:

AAAA-BBBB-CCCC

不断尝试

必须:

  • Rate Limit
  • Hash存储
  • IP限制
  • 失败记录

二、最终License架构

整体:

                Server


                  |

                  |


        License Generator


                  |

                  |


        License Database


                  |

                  |


        RSA/ECDSA Signature


                  |

                  |

        License Key


                  |

                  |

             Client SDK


                  |

                  |

          Signature Verify

三、License数据模型设计

新增:

Domain/Entities

创建:

License.cs

四、License实体

namespace LicenseServer.Domain.Entities;


public class License
{


public Guid Id {get;set;}



/// <summary>
/// 用户
/// </summary>

public Guid UserId {get;set;}



/// <summary>
/// 产品
/// </summary>

public Guid ProductId {get;set;}



/// <summary>
/// License编号
/// </summary>

public string LicenseCode {get;set;}="";



/// <summary>
/// Hash后的Key
/// </summary>

public string LicenseHash {get;set;}="";



/// <summary>
/// 最大设备数量
/// </summary>

public int MaxDevices {get;set;}



/// <summary>
/// 有效期
/// </summary>

public DateTime ExpireAt {get;set;}



/// <summary>
/// 状态
/// </summary>

public LicenseStatus Status {get;set;}



/// <summary>
/// 数字签名
/// </summary>

public string Signature {get;set;}="";



public DateTime CreatedAt {get;set;}
=DateTime.UtcNow;



public User User {get;set;}=null!;


}

五、License状态枚举

创建:

Enums/LicenseStatus.cs
public enum LicenseStatus
{

Active=1,


Suspended=2,


Expired=3,


Revoked=4


}

六、设备绑定模型

创建:

Device.cs
public class Device
{


public Guid Id {get;set;}


public Guid LicenseId {get;set;}



/// <summary>
/// 机器指纹
/// </summary>

public string Fingerprint {get;set;}="";



public string DeviceName {get;set;}="";



public string OS {get;set;}="";



public DateTime ActivatedAt {get;set;}
=DateTime.UtcNow;



public DateTime LastSeenAt {get;set;}



public License License {get;set;}=null!;


}

七、数据库关系

最终:

User

 |

 |

License

 |

 |

Device

一个用户:

User A


License:

Professional


Devices:

PC-001

MacBook

Laptop

八、License Key设计

用户看到:

48D0-61CD-35FE-9C9B-5358-3725-D644-1A18

长度:

8组 × 4字符

共:

32字符

九、不要直接存储License

错误:

数据库:

license_code

48D0-61CD...

原因:

数据库泄露:

所有License泄露。


正确:

数据库:

LicenseHash:

SHA256(
license_code
)

十、License生成算法

流程:

Random Bytes

        |

        |

Base32 Encode

        |

        |

格式化

        |

        |

签名

        |

        |

保存Hash

十一、LicenseGenerator实现

Application:

创建:

Services/LicenseGenerator.cs

代码:

using System.Security.Cryptography;


public class LicenseGenerator
{


public string Generate()
{


var bytes =
RandomNumberGenerator
.GetBytes(20);



var code =
Convert.ToHexString(bytes);



return Format(code);


}



private string Format(string value)
{


value=value[..32];


var groups =
Enumerable.Range(0,8)
.Select(i =>
value.Substring(i*4,4));



return string.Join("-",groups);


}


}

生成:

例如:

输入随机:

48D061CD35FE9C9B53583725D6441A18

输出:

48D0-61CD-35FE-9C9B-5358-3725-D644-1A18

十二、License Hash

创建:

CryptoService.cs
using System.Security.Cryptography;
using System.Text;


public class CryptoService
{


public string SHA256(
string value)
{


using var sha=
SHA256.Create();


var bytes=
sha.ComputeHash(
Encoding.UTF8.GetBytes(value));



return Convert.ToHexString(bytes);


}


}

十三、数字签名设计

这里非常重要。

不要:

AES加密License

原因:

客户端必须解密。

推荐:

非对称密码

使用:

ECDSA P-256

或者:

RSA-3072

推荐:

商业软件:

ECDSA P-256

原因:

  • 签名小
  • 验证快
  • 适合客户端

十四、密钥架构

服务器:

保存:

Private Key

例如:

Vault:

license-sign-private-key

客户端:

内置:

Public Key

关系:

Server Private Key

        |

        |

      Sign


        |

        |

License


        |

        |

Client Public Key

        |

        |

     Verify

十五、License Payload设计

签名前:

JSON:

{

"licenseId":

"92cxxx",


"product":

"Professional",


"user":

"user@test.com",


"devices":

3,


"expire":

"2027-01-01"


}

签名:

ECDSA(payload)

生成:

signature

十六、License创建服务

接口:

public interface ILicenseService
{


Task<License>
CreateAsync(
Guid userId,
Guid productId);



Task<bool>
ActivateAsync(
string license,
string fingerprint);



}

十七、创建License流程

管理员:

点击:

Create License

执行:

生成Key



生成Payload



签名



Hash Key



保存数据库



发送邮件

十八、激活API设计

客户端调用:

POST

/api/license/activate

请求:

{

"license":

"48D0-61CD-35FE...",


"fingerprint":

"PC-A82F92XX",


"deviceName":

"DESKTOP-001",


"os":

"Windows 11"

}

返回:

成功:

{

"success":

true,


"license":

{

"expire":

"2027-01-01",

"features":

[

"pro"

]

}

}

失败:

{

"success":

false,


"error":

"DEVICE_LIMIT"

}

十九、激活核心逻辑

伪代码:

public async Task<bool>
ActivateAsync(
string key,
string fingerprint)
{


var hash =
_crypto.Hash(key);



var license =
await db.Licenses
.FirstOrDefaultAsync(
x=>x.LicenseHash==hash);



if(license==null)

return false;



if(license.Status
!=Active)

return false;



var devices =
await db.Devices
.CountAsync(
x=>x.LicenseId
==license.Id);



if(devices>=license.MaxDevices)

return false;



保存设备();


return true;


}

二十、设备重复激活

情况:

用户重新安装:

旧设备:

PC-001

再次激活:

检查:

Fingerprint存在

则:

更新:

LastSeenAt

不增加设备。


二十一、Heartbeat机制

防止:

用户复制License。

客户端:

每天:

POST

/api/license/heartbeat

数据:

{

licenseId:

"xxx",


fingerprint:

"xxx"

}

服务器:

更新:

LastSeenAt

二十二、防爆破设计

激活接口:

必须:

限流

例如:

IP:

一分钟10次

用户:

一天100次

失败记录

表:

LicenseActivationAttempt

字段:

IP

LicenseHash

Time

Success

二十三、Redis缓存

激活查询:

缓存:

license_hash



license info

减少:

PostgreSQL压力。


二十四、客户端验证策略

客户端:

启动:

读取License缓存



验证签名



检查过期



在线Heartbeat



启动软件

二十五、本阶段完成

功能 状态
License数据模型
License Key生成
Hash存储
ECDSA签名设计
设备绑定
激活API设计
多设备限制
Heartbeat设计
防爆破设计

当前系统能力

现在已经具备:

用户系统

      +

License Engine

      +

设备限制

      +

数字签名

下一阶段:

第九部分(四):客户端 SDK 完整实现

将开始编写:

  1. C# License SDK
  2. License文件格式
  3. 本地加密存储
  4. ECDSA公钥验证
  5. 设备指纹生成
  6. 在线激活客户端
  7. 离线激活
  8. Heartbeat
  9. 自动续期
  10. Windows/macOS/Linux客户端集成方式

完成后,你的软件端就可以真正接入这个授权系统。

LicenseServer 商业授权系统开发实战文档 v1.0

第九部分(四):客户端 SDK 完整实现

本阶段实现:

给你的桌面软件提供一个商业级 License SDK。

目标:

你的软件开发者只需要:

LicenseManager.Initialize();

var result =
await LicenseManager.ActivateAsync(
    licenseKey
);

if(result.Success)
{
    StartApplication();
}

即可完成授权。


一、客户端 SDK 设计目标

SDK需要解决:

1. License激活

支持:

在线:

输入License Key



连接服务器



绑定设备



保存授权

2. 本地验证

软件启动:

不能每次联网。

流程:

启动软件



读取本地License



验证数字签名



检查有效期



启动

3. 防破解

客户端不能保存:

明文:

License Key

不能:

license.json

保存:

必须:

加密License Cache

4. 多平台

支持:

Windows

macOS

Linux

.NET:

推荐:

.NET 10

框架:

Class Library

二、SDK工程结构

创建:

client-sdk/


LicenseSDK/


├── LicenseManager.cs


├── LicenseClient.cs


├── DeviceFingerprint.cs


├── LicenseStorage.cs


├── Crypto/



├── SignatureVerifier.cs



└── HashService.cs



├── Models/



├── LicenseInfo.cs



└── ActivationResult.cs



├── Exceptions/


└── LicenseException.cs

三、创建SDK项目

根目录:

mkdir client-sdk

cd client-sdk

dotnet new classlib \
-n LicenseSDK

加入Solution:

dotnet sln add \
client-sdk/LicenseSDK

四、SDK目标框架

csproj:

<TargetFrameworks>

net10.0;

net10.0-windows;

net10.0-macos;

net10.0-linux

</TargetFrameworks>

这样:

Windows:

WPF

Avalonia

macOS:

MAUI

Avalonia

Linux:

Avalonia

都可以使用。


五、License数据模型

Models:

创建:

LicenseInfo.cs

代码:

namespace LicenseSDK.Models;


public class LicenseInfo
{


public string LicenseId
{
get;set;
}="";


public string Product
{
get;set;
}="";


public DateTime ExpireAt
{
get;set;
}


public string[] Features
{
get;set;
}=[];


}

六、ActivationResult

创建:

ActivationResult.cs
public class ActivationResult
{


public bool Success
{
get;set;
}


public string Message
{
get;set;
}="";


public LicenseInfo?
License
{
get;set;
}


}

七、设备指纹生成

这是商业授权关键。

目标:

同一台机器:

生成稳定ID。


不推荐

不要:

CPU序列号

硬盘序列号

MAC地址

原因:

  • 用户权限不足
  • 虚拟机变化
  • 隐私问题

推荐组合:

MachineId

+

OS信息

+

随机安装ID

八、本地Machine ID

Windows:

读取:

Registry

HKLM\SOFTWARE\Microsoft\
Cryptography

MachineGuid

Linux:

/etc/machine-id

macOS:

IOPlatformUUID

九、DeviceFingerprint实现

创建:

DeviceFingerprint.cs

代码:

using System.Security.Cryptography;
using System.Text;


namespace LicenseSDK;


public class DeviceFingerprint
{


public static string Generate()
{


var machineId =
GetMachineId();



var raw =
$"{machineId}-{Environment.OSVersion}-{Environment.MachineName}";



using var sha=
SHA256.Create();



var hash=
sha.ComputeHash(
Encoding.UTF8.GetBytes(raw));



return Convert.ToHexString(hash);

}


private static string GetMachineId()
{

return Environment.MachineName;

}


}

生产版本:

这里需要分别实现:

WindowsProvider

LinuxProvider

MacProvider

十、License本地存储

目录:

Windows:

%ProgramData%/Company/App/license

macOS:

~/Library/Application Support/App/license

Linux:

~/.config/app/license

十一、为什么不用Registry?

因为:

注册表:

容易:

导出

修改

删除

推荐:

加密文件。


十二、LicenseStorage

创建:

LicenseStorage.cs

代码:

public class LicenseStorage
{


private readonly string path;


public LicenseStorage()
{

path=
GetPath();

}



public void Save(
string data)
{

File.WriteAllText(
path,
data);

}



public string?
Load()
{

if(!File.Exists(path))
return null;


return File.ReadAllText(path);

}



}

十三、本地加密

Windows:

使用:

DPAPI

macOS:

使用:

Keychain

Linux:

使用:

Secret Service API

统一:

SDK:

IStorageEncryption

接口:

public interface IStorageEncryption
{


string Encrypt(
string data);


string Decrypt(
string data);


}

十四、ECDSA签名验证

服务器:

私钥:

Private Key

客户端:

公钥:

Public Key

创建:

SignatureVerifier.cs

代码:

using System.Security.Cryptography;


public class SignatureVerifier
{


public bool Verify(
string payload,
string signature)
{


using var ecdsa=
ECDsa.Create();



ecdsa.ImportSubjectPublicKeyInfo(
Convert.FromBase64String(
PublicKey),
out _);



return ecdsa.VerifyData(

Encoding.UTF8.GetBytes(payload),

Convert.FromBase64String(signature),

HashAlgorithmName.SHA256

);


}



private const string PublicKey=
"SERVER_PUBLIC_KEY";


}

十五、LicenseClient

负责网络通信。

创建:

LicenseClient.cs

依赖:

HttpClient。


代码:

public class LicenseClient
{


private readonly HttpClient client;


public LicenseClient(
HttpClient client)
{

this.client=client;

}



public async Task<
ActivationResult>
ActivateAsync(
string key,
string fingerprint)
{


var response=
await client.PostAsJsonAsync(
"/api/license/activate",
new
{

license=key,

fingerprint

});



return await response
.Content
.ReadFromJsonAsync
<ActivationResult>();

}


}

十六、LicenseManager核心

这是用户调用入口。

创建:

LicenseManager.cs

代码:

public class LicenseManager
{


private readonly LicenseClient client;


private readonly LicenseStorage storage;



public async Task<bool>
ActivateAsync(
string key)
{


var fingerprint=
DeviceFingerprint.Generate();



var result=
await client.ActivateAsync(
key,
fingerprint);



if(!result.Success)
return false;



storage.Save(
JsonSerializer.Serialize(
result.License));



return true;


}



public bool ValidateLocal()
{


var license=
storage.Load();



if(license==null)

return false;



return true;


}


}

十七、软件集成方式

你的软件:

例如:

PhotoEditor.exe

启动:

static async Task Main()
{


var license=
new LicenseManager();


if(!license.ValidateLocal())
{

Console.WriteLine(
"需要激活");


return;

}



StartApp();


}

十八、在线激活流程

完整流程:

用户输入Key




SDK生成Fingerprint




POST /activate




服务器验证




设备绑定




返回License Payload




验证Signature




加密保存




启动软件

十九、离线激活设计

商业软件必须支持。

流程:

用户:

生成:

Request File


machine.req

发送给你。

服务器:

生成:

license.dat

用户导入。


二十、离线License格式

例如:

{
payload:
{

product:"Pro",

expire:"2027"


},


signature:

"xxxxx"

}

客户端:

只验证:

Signature

不需要联网。


二十一、Heartbeat机制

在线软件:

启动:

每24小时

调用:

/api/license/heartbeat

发送:

{

licenseId,

fingerprint

}

二十二、SDK防破解增强

商业版增加:

1. 混淆

.NET:

推荐:

  • Eazfuscator.NET
  • Dotfuscator

2. 关键代码拆分

不要:

if(valid)
unlock();

改:

LicenseService



FeatureService



RuntimeCheck

3. 内存保护

避免:

明文:

License Key


4. Anti Debug

检测:

  • Debugger
  • Dump
  • Patch

二十三、SDK NuGet发布

最终:

发布:

Company.License.SDK

使用:

<PackageReference
Include="Company.License.SDK"
Version="1.0.0"
/>

二十四、本阶段完成

功能 状态
SDK架构
License激活
设备指纹
本地缓存
签名验证
在线授权
离线授权设计
Heartbeat设计
NuGet发布方案

当前系统能力

现在已经形成:

用户系统

+

License Server

+

License Engine

+

Client SDK


=


完整商业授权平台

下一阶段:

第九部分(五):生产级安全加固

将进入商业软件真正上线前最重要部分:

内容:

  1. 私钥安全管理(Vault/HSM)
  2. License密钥防泄露
  3. API防攻击
  4. 防爆破体系
  5. WAF设计
  6. 数据库安全
  7. 审计日志
  8. 管理员权限隔离
  9. 客户端反调试
  10. 代码混淆策略
  11. 安全测试流程
  12. 商业软件漏洞响应机制

这一部分完成后,系统安全等级才达到真正商业发行标准。

LicenseServer 商业授权系统开发实战文档 v1.0

第九部分(五):生产级安全加固

本阶段进入商业发行前最后一个关键环节:

将一个“能工作的授权系统”,提升到“可以卖给客户的商业授权平台”。

目标:

完成:

✅ 密钥安全体系 ✅ 服务端防攻击 ✅ API安全 ✅ 数据库安全 ✅ 管理后台安全 ✅ 审计体系 ✅ 客户端防破解增强 ✅ 安全测试流程


一、安全架构重新设计

生产环境不能是:

 id="old-security"
API Server

    |

Database

    |

Private Key

原因:

如果服务器被入侵:

攻击者可能获得:

  • 数据库
  • License生成能力
  • 私钥

生产架构:

 id="secure-architecture"

             Internet


                |


          Cloudflare WAF


                |


          Nginx Gateway


                |


        ASP.NET Core API


        /           \


       /             \


 PostgreSQL        Vault


                    |

                    |

             License Private Key

二、核心原则:私钥永远不能暴露

这是整个系统最重要原则。

错误设计

例如:

 id="bad-private-key"

var privateKey=
"MIIC....";

然后:

发布到服务器。

风险:

  • Git泄露
  • 服务器泄露
  • 运维人员读取

三、正确方案:HashiCorp Vault

架构:

 id="vault-flow"

License API


    |

    |

 Vault Authentication


    |

    |

Private Key

API:

需要签名时:

请求:

 id="vault-request"

Generate License Signature

Vault:

返回:

 id="vault-response"

Signature

API:

不知道私钥。


四、Vault部署

Docker:

 id="vault-docker"

services:


 vault:


  image:

   hashicorp/vault:latest


  container_name:

   license-vault


  cap_add:

   - IPC_LOCK


  ports:

   - "8200:8200"

启动:

 id="vault-start"

docker compose up -d vault

初始化:

 id="vault-init"

vault operator init

保存:

 id="vault-key"

Unseal Keys

Root Token

注意:

不要保存:

  • Git
  • 文档
  • 网盘

推荐:

密码管理器。


五、密钥分类管理

生产环境:

至少:

 id="key-level"

Vault


├── License Signing Key

├── JWT Secret

├── Database Password

├── SMTP Password

└── Payment Secret

六、License签名密钥升级

推荐:

ECDSA P-256

密钥:

 id="ecdsa"

Private Key

Server Only



Public Key

Client SDK

七、密钥轮换机制

商业系统必须考虑:

如果私钥泄露怎么办?

设计:

Key Version。

例如:

 id="key-version"

{

"keyId":

"2026-v1",


"algorithm":

"ECDSA-P256"

}

客户端:

保存:

 id="multi-key"

PublicKey-v1

PublicKey-v2

升级:

不用重新发布软件。


八、API安全加固

1. HTTPS强制

生产:

只允许:

 id="tls"

TLS 1.3

禁止:

TLS 1.0

TLS 1.1

Nginx:

 id="nginx-tls"

ssl_protocols TLSv1.3;

九、API Rate Limit

重点接口:

激活接口

攻击:

 id="attack"

POST /license/activate

10000次/分钟

限制:

普通用户:

 id="limit"

10 requests/min

IP:

 id="ip-limit"

60 requests/min

使用:

ASP.NET Core RateLimiter。

安装:

无需第三方。

Program.cs:

 id="rate-limit"

builder.Services
.AddRateLimiter(options =>
{

options.AddFixedWindowLimiter(
"license",
config =>
{

config.PermitLimit=10;

config.Window=
TimeSpan.FromMinutes(1);


});


});

启用:

 id="enable-rate"

app.UseRateLimiter();

十、License爆破防护

攻击:

尝试:

AAAA-BBBB-CCCC

AAAA-BBBB-CCCD

AAAA-BBBB-CCCE

防护:

1. 不保存明文Key

数据库:

 id="hash-only"

SHA256(Key)

2. 延迟响应

失败:

第一次:

100ms

连续失败:

5s

3. IP黑名单

Redis:

保存:

 id="redis-ban"

failed:

IP

count

expire

十一、数据库安全

PostgreSQL配置

禁止:

公网访问。

错误:

 id="wrong-db"

0.0.0.0:5432

正确:

 id="right-db"

API Container

        |

        |

PostgreSQL Network

十二、数据库账号权限

不要:

 id="bad-db-user"

postgres

生产:

创建:

 id="db-user"

license_api

权限:

只有:

SELECT

INSERT

UPDATE

DELETE

没有:

CREATE DATABASE

SUPERUSER

十三、数据库加密

敏感字段:

例如:

邮箱:

可选择:

应用层加密。

结构:

 id="encrypt-field"

Email

    |

AES-256

    |

Database

十四、Admin后台安全

Admin是最高风险区域。

必须:

MFA

管理员登录:

密码:

TOTP。

例如:

Google Authenticator。


IP限制

例如:

管理员:

只允许:

 id="admin-ip"

公司IP

VPN IP

操作确认

危险操作:

例如:

删除License。

要求:

二次确认。


十五、RBAC权限细化

不要只有:

 id="simple-role"

Admin

生产:

 id="roles"

SuperAdmin


|

LicenseManager


|

Support


|

Finance


|

ReadOnly

权限表:

 id="permission"

Role

Permission

例如:

Support:

允许:

查看用户

查看License

禁止:

生成License

退款

十六、审计日志系统

商业软件必须有。

记录:

 id="audit"



什么时候

什么IP

做了什么

结果

例如:

 id="audit-json"

{

"user":

"admin@test.com",


"action":

"CREATE_LICENSE",


"time":

"2026-08-11",


"ip":

"1.2.3.4"

}

数据库:

 id="audit-table"

AuditLogs


Id

UserId

Action

IPAddress

CreatedAt

十七、日志安全

不要记录:

禁止:

 id="no-log"

License Key

Password

Token

可以:

 id="yes-log"

LicenseId

UserId

Result

十八、客户端安全增强

服务端安全之后:

客户端也是重点。


十九、代码混淆

.NET推荐:

商业:

  • Eazfuscator.NET
  • Babel Obfuscator

免费:

  • ConfuserEx

作用:

保护:

 id="protect"

License逻辑

算法

API地址

二十、防调试

检测:

 id="debug"

Debugger.IsAttached

但是:

不要作为唯一保护。

原因:

容易绕过。


二十一、关键逻辑拆分

不要:

 id="bad-check"

if(valid)
{

unlock();

}

改:

 id="split"

LicenseValidator


        |


FeatureManager


        |


RuntimeGuard


        |

Application

二十二、本地License保护

保存:

不要:

 id="plain"

license.json

改:

 id="secure"

license.dat

AES-256-GCM

密钥:

Windows:

DPAPI

macOS:

Keychain

Linux:

Secret Service


二十三、防时间回拨

攻击:

修改系统时间。

解决:

保存:

 id="time"

LastServerTime

LastLocalTime

检测:

 id="rollback"

current < previous

判定异常。


二十四、离线授权安全

离线License:

必须:

包含:

 id="offline"

{

LicenseId,

MachineFingerprint,

Expire,

Signature

}

不能:

只保存:

 id="bad-offline"

Expire=2099

二十五、安全测试流程

上线前:

必须测试。


1. API扫描

工具:

  • OWASP ZAP
  • Burp Suite

检查:

  • SQL Injection
  • XSS
  • CSRF
  • JWT漏洞

2. 依赖扫描

.NET:

 id="dotnet-audit"

dotnet list package
--vulnerable

Node:

 id="npm-audit"

bun audit

3. Docker扫描

Trivy:

 id="trivy"

trivy image license-api

二十六、备份策略

数据库:

每天:

 id="backup"

Full Backup

保留:

 id="retain"

7天

30天

90天

二十七、灾难恢复

必须测试:

不是:

“有备份”。

而是:

 id="restore"

新服务器



恢复数据库



恢复Vault



启动服务



验证License

二十八、生产安全Checklist

上线前:

Server

✅ HTTPS

✅ Firewall

✅ SSH Key登录

✅ 禁止root登录


API

✅ JWT

✅ Rate Limit

✅ Audit Log

✅ Input Validation


Database

✅ 私网

✅ 最小权限

✅ 自动备份


License

✅ Hash存储

✅ ECDSA签名

✅ Key轮换


Client

✅ 混淆

✅ 本地加密

✅ 防时间回拨


二十九、本阶段完成

模块 完成
Vault密钥管理
ECDSA密钥体系
API防护
爆破防护
数据库安全
Admin安全
审计系统
客户端增强
安全测试流程

当前系统等级

现在:

普通授权系统



商业级License平台



企业软件授权架构

下一阶段:

第九部分(六):支付系统 + 自动发货 + 商业闭环实现

将实现:

  1. 产品套餐设计
  2. Stripe/Paddle支付接入
  3. Webhook安全验证
  4. 支付成功自动生成License
  5. 邮件自动发送
  6. 订单系统
  7. 退款处理
  8. 订阅续费
  9. License升级降级
  10. 商业运营后台

完成这一部分后,整个系统将从“技术平台”变成真正可以销售的软件商业系统。

LicenseServer 商业授权系统开发实战文档 v1.0

第九部分(六):支付系统 + 自动发货 + 商业闭环实现

本阶段开始把 LicenseServer 从:

“技术授权平台”

升级为:

“可直接销售软件的商业闭环系统”。

完成后流程:

用户访问官网



选择软件版本



在线支付



支付平台确认



自动创建订单



自动生成License



邮件发送激活码



用户下载安装



激活软件



续费 / 升级 / 售后

一、商业模式设计

首先设计产品模型。

不要把License和支付直接绑定。

正确:

Product

产品



Plan

套餐



Order

订单



License

授权

关系:

Product

  |
  |

Plan

  |
  |

Order

  |
  |

License

二、产品模型设计

例如:

软件:

PhotoManager Pro

套餐:

套餐 价格 设备
Personal $29 1台
Professional $79 3台
Business $199 5台
Enterprise 联系销售 无限

三、数据库设计扩展

新增:

Order

Payment

Product

Plan

Invoice

Subscription

Coupon

四、Product实体

Domain:

创建:

Entities/Product.cs
public class Product
{

public Guid Id {get;set;}


public string Name {get;set;}="";


public string Description {get;set;}="";


public bool Active {get;set;}=true;


public DateTime CreatedAt {get;set;}
=DateTime.UtcNow;


}

五、Pricing Plan实体

创建:

Plan.cs
public class Plan
{

public Guid Id {get;set;}


public Guid ProductId {get;set;}


public string Name {get;set;}="";


public decimal Price {get;set;}


public string Currency {get;set;}
="USD";


public int MaxDevices {get;set;}


public int ValidDays {get;set;}


public Product Product {get;set;}=null!;

}

六、Order订单模型

创建:

Order.cs
public class Order
{


public Guid Id {get;set;}


public Guid UserId {get;set;}



public string OrderNo {get;set;}="";



public decimal Amount {get;set;}



public string Currency {get;set;}
="USD";



public OrderStatus Status {get;set;}



public string PaymentProvider {get;set;}="";



public string PaymentId {get;set;}="";



public DateTime CreatedAt {get;set;}
=DateTime.UtcNow;


}

七、订单状态

public enum OrderStatus
{

Pending=0,


Paid=1,


Failed=2,


Refunded=3,


Cancelled=4


}

八、支付架构设计

推荐支持:

第一阶段

Stripe

适合:

  • 欧美客户
  • SaaS
  • 国际支付

第二阶段

Paddle

优势:

Merchant of Record。

处理:

  • VAT
  • 税务
  • 发票

国内:

可以增加:

  • 支付宝
  • 微信支付

九、支付流程

以Stripe为例:

用户点击购买




创建Order




创建Stripe Checkout Session




跳转支付页面




用户付款




Stripe Webhook




验证签名




更新Order Paid




生成License




发送邮件

十、不要相信前端支付结果

错误:

if(paymentSuccess)
{
createLicense();
}

原因:

用户可以修改JS。


正确:

只相信:

Payment Provider Webhook

十一、Stripe SDK安装

Backend:

dotnet add package Stripe.net

十二、Stripe配置

环境变量:

STRIPE_SECRET_KEY

STRIPE_WEBHOOK_SECRET

不要:

写入:

appsettings.json

十三、Payment Service设计

Application:

创建:

IPaymentService.cs
public interface IPaymentService
{

Task<string>
CreateCheckoutAsync(
Guid orderId);


Task HandleWebhookAsync(
string json,
string signature);


}

十四、创建支付订单

流程:

用户购买:

Professional

服务器:

创建:

{
orderId:

"xxxx",

amount:

79,

currency:

"usd"

}

Stripe:

返回:

checkout_url

用户跳转:

stripe.com/payment/xxx

十五、Webhook处理

接口:

POST

/api/payment/webhook

接收:

Stripe事件。

例如:

{

"type":

"checkout.session.completed"

}

十六、Webhook安全验证

必须:

验证:

Stripe-Signature

不能:

直接:

PaymentSuccess();

流程:

Webhook



验证Signature



确认Event



检查Order



更新状态

十七、订单支付完成

成功:

数据库:

Order:

Status=Paid

然后:

进入:

License生成队列。


十八、自动发货架构

不要:

支付接口里直接生成。

错误:

Webhook



Generate License



Send Email

原因:

Webhook可能超时。


正确:

消息队列:

Webhook



Order Paid Event



Queue



Worker



Generate License



Send Email

十九、后台任务Worker

.NET:

使用:

BackgroundService

结构:

LicenseServer.Worker

负责:

  • 发License
  • 邮件
  • 清理任务

二十、支付事件

定义:

public class OrderPaidEvent
{

public Guid OrderId {get;set;}

}

二十一、License自动生成

Worker:

读取Order




获取Plan




CreateLicense()




保存




绑定User




发送邮件

二十二、邮件系统

推荐:

生产:

  • Amazon SES
  • SendGrid
  • Mailgun

开发:

Mailhog。


二十三、邮件模板

购买成功:

感谢购买。


订单号:

XXXX


License:

XXXX-XXXX-XXXX


下载地址:

https://xxx.com/download

二十四、邮件安全

不要发送:

管理员密码。

License邮件:

建议:

发送:

License ID

下载链接

激活说明

完整Key:

可选择:

显示一次。


二十五、License找回系统

用户:

登录网站。

进入:

My Licenses

查看:

购买记录

License状态

设备数量

二十六、找回机制

不要:

通过邮箱直接返回:

License Key。

原因:

邮箱泄露风险。

推荐:

登录账户:

查看。


二十七、退款流程

流程:

Customer Request Refund




Admin Review




Payment Refund




Webhook




License Revoked

二十八、退款后授权处理

状态:

License

Active



Suspended



Revoked

客户端:

Heartbeat:

发现:

REVOKED

停止运行。


二十九、订阅模式设计

未来支持:

月付:

$9/month

年付:

$79/year

新增:

Subscription。


三十、Subscription模型

public class Subscription
{


public Guid Id {get;set;}


public Guid UserId {get;set;}


public string ProviderId {get;set;}="";


public DateTime StartAt {get;set;}


public DateTime NextBillingAt {get;set;}


public bool Active {get;set;}


}

三十一、License升级

例如:

用户:

Personal

升级:

Professional。

计算:

Professional价格

-

已经支付金额

生成:

新License。

旧:

Expired

三十二、优惠券系统

数据库:

Coupon:

Code

Discount

Expire

MaxUsage

三十三、商业后台增加

Admin:

增加菜单:

销售管理

订单管理

支付记录

退款

优惠券

收入统计

三十四、财务统计

统计:

Daily Revenue

Monthly Revenue

Active Users

Conversion Rate

Refund Rate

三十五、完整商业闭环

最终:

访问官网



注册账户



选择套餐



支付



Webhook确认



Order Paid



Worker



生成License



邮件发送



客户端下载



激活



设备管理



续费升级



收入统计

三十六、本阶段完成

模块 状态
Product设计
Plan套餐
Order系统
Stripe支付
Webhook安全
自动发货
邮件系统
退款流程
订阅设计
商业后台需求

当前系统完整度

目前已经完成:

用户系统
+
License Engine
+
Client SDK
+
安全体系
+
支付闭环

=

商业授权平台

下一阶段:

第九部分(七):Admin Console 完整实现

将开发:

  1. Next.js Admin架构
  2. 管理员登录
  3. RBAC权限管理
  4. 用户管理
  5. License管理
  6. 设备管理
  7. 订单管理
  8. 支付管理
  9. 审计日志查看
  10. 数据统计Dashboard

完成后,你将拥有完整的商业运营后台。

LicenseServer 商业授权系统开发实战文档 v1.0

第九部分(七):Admin Console 完整实现

本阶段实现:

商业授权平台管理员控制中心(Admin Console)

目标:

让运营人员无需访问数据库,通过Web后台完成:

  • 用户管理
  • License管理
  • 产品管理
  • 订单管理
  • 支付管理
  • 设备管理
  • 权限管理
  • 审计查看
  • 数据分析

最终架构:

                 Admin User

                    |

                    |

             Next.js Admin Console

                    |

                    |

             ASP.NET Core API

                    |

        +-----------+-----------+

        |                       |

   PostgreSQL              Redis

一、技术选型

Admin Console:

推荐:

功能 技术
前端框架 Next.js 16
语言 TypeScript
UI shadcn/ui
样式 Tailwind CSS
数据请求 TanStack Query
表格 TanStack Table
图表 Recharts
认证 JWT + HttpOnly Cookie

理由:

和商业SaaS后台技术路线一致。


二、工程结构

创建:

admin-console/

├── app/


├── login/


├── dashboard/


├── users/


├── licenses/


├── orders/


├── products/


├── audit/


├── settings/


├── components/


├── lib/


├── hooks/


├── types/


├── middleware.ts


└── package.json

三、创建Next.js项目

环境:

Node:

推荐:

Node.js 24 LTS

或者:

Bun 1.2+

创建:

bun create next-app admin-console

选择:

✔ TypeScript

✔ App Router

✔ Tailwind CSS

✔ ESLint

四、安装依赖

bun add \
@tanstack/react-query \
axios \
zod \
react-hook-form

UI:

bunx shadcn@latest init

添加:

bunx shadcn@latest add \
button \
card \
table \
dialog \
form \
dropdown-menu

五、目录设计

推荐:

app

├── (auth)


└── login


├── (admin)


├── dashboard

├── users

├── licenses

├── orders


components

lib

services

types

六、管理员登录设计

流程:

Admin



输入账号密码



API验证



生成JWT



HttpOnly Cookie



进入后台

七、为什么不用LocalStorage保存Token?

错误:

localStorage.setItem(
"token",
jwt
)

风险:

XSS可以读取。


推荐:

Cookie:

Set-Cookie:

access_token=xxx;

HttpOnly;

Secure;

SameSite=Strict

八、登录页面

路径:

/login

结构:

+----------------+

 Email

 Password


 [ Login ]

+----------------+

组件:

<LoginForm />

九、API Client封装

创建:

lib/api.ts

代码:

import axios from "axios";


export const api =
axios.create({

baseURL:
process.env
.NEXT_PUBLIC_API_URL,


withCredentials:true

});

十、Dashboard主页

路径:

/dashboard

显示:

核心指标:

Users

Licenses

Orders

Revenue

Active Devices

页面:

+-----------------------+

 Users        12000

 Licenses      9800


 Revenue    $24000


 Active       8500


+-----------------------+

十一、Dashboard API

Backend:

增加:

GET

/api/admin/dashboard

返回:

{

users:12000,

licenses:9800,

revenue:24000,

devices:8500

}

十二、用户管理

路径:

/users

功能:

  • 搜索用户
  • 查看详情
  • 禁用账户
  • 重置密码
  • 查看License

列表:

Email 状态 注册时间
test@gmail.com Active 2026-01

十三、用户详情页

路径:

/users/{id}

显示:

用户信息


Email


Created


Last Login



Licenses


Devices


Orders

十四、License管理

路径:

/licenses

功能:

查看

字段:

字段
License ID
用户
产品
状态
设备数量
过期时间

操作

管理员可以:

  • 创建License
  • 禁用License
  • 恢复License
  • 删除测试License

十五、创建License页面

表单:

用户:

[选择]


产品:

[Professional]


设备数量:

[3]


有效期:

[365天]


[Create]

调用:

POST

/api/admin/licenses

十六、License详情

显示:

License:


48D0-61CD...


Status:

Active


Devices:

2/3


Created:

2026

设备:

PC-001

Windows11

Last Seen

2026-08-10


MacBook

macOS

2026-08-09

十七、设备管理

路径:

/devices

功能:

  • 查看设备
  • 强制解绑
  • 查看IP
  • 查看最后在线时间

十八、订单管理

路径:

/orders

显示:

订单 金额 状态
ORD001 79 USD Paid

操作:

  • 查看支付信息
  • 退款
  • 重新发送License

十九、支付管理

显示:

Stripe Payment ID

Amount

Currency

Created

Status

二十、产品管理

路径:

/products

管理:

产品:

PhotoManager Pro

套餐:

Personal

Professional

Enterprise

二十一、RBAC权限系统

后台用户:

不要只有Admin。

设计:

SuperAdmin

|

Admin

|

Support

|

Finance

|

Viewer

二十二、权限数据库

新增:

AdminUser


Role


Permission


RolePermission

例如:

Support:

允许:

查看用户

查看License

禁止:

生成License

退款

二十三、前端权限控制

例如:

<Permission
name="license.create"
>

<CreateButton />

</Permission>

二十四、审计日志页面

路径:

/audit

显示:

时间

管理员

IP

操作

结果

例如:

2026-08-10

admin

CREATE_LICENSE

SUCCESS

二十五、安全设置页面

路径:

/settings/security

功能:

  • 修改密码
  • MFA绑定
  • 登录设备
  • API Key管理

二十六、管理员MFA

流程:

输入密码



TOTP验证



进入后台

数据库:

增加:

TwoFactorEnabled

SecretKey

二十七、文件上传安全

后台上传:

例如:

软件安装包。

必须:

限制:

文件类型

文件大小

病毒扫描

二十八、Dashboard数据图表

推荐:

Recharts。

显示:

收入趋势

Jan

Feb

Mar

Apr

License增长

New License

Active License

Expired

二十九、后台API安全

所有:

/api/admin/*

必须:

[Authorize(
Roles="Admin"
)]

进一步:

Permission:

[RequirePermission(
"license.delete"
)]

三十、Docker部署

Admin Console:

Dockerfile:

FROM node:24-alpine


WORKDIR /app


COPY . .


RUN npm install


RUN npm run build


CMD [
"npm",
"start"
]

三十一、docker-compose

admin:


 image:
 license-admin


 ports:

 - "3000:3000"


 environment:

 NEXT_PUBLIC_API_URL:

 https://api.example.com

三十二、CI/CD

GitHub Actions:

流程:

Push




Build




Test




Docker Build




Push Registry




Deploy

三十三、生产部署建议

推荐:

结构:

Cloudflare

    |

Nginx

    |

Next.js Admin

    |

ASP.NET API

    |

PostgreSQL

三十四、后台性能优化

数据列表:

不要一次加载:

100000用户。

使用:

分页:

GET

/users?page=1&pageSize=50

搜索:

使用:

PostgreSQL:

GIN Index

三十五、缓存策略

Dashboard:

Redis:

缓存:

dashboard_stats

60秒

三十六、本阶段完成

模块 状态
Next.js Admin
管理员登录
JWT Cookie认证
Dashboard
用户管理
License管理
订单管理
支付管理
RBAC
审计日志
MFA设计
Docker部署

当前系统完成度

目前已经拥有:

                官网

                 |

              支付系统

                 |

              License Server

                 |

              Client SDK

                 |

             Admin Console


=


完整商业软件授权生态

下一阶段:

第九部分(八):生产部署上线方案

将进入最终上线阶段:

内容:

  1. 云服务器架构设计
  2. Docker Compose生产部署
  3. PostgreSQL高可用
  4. Redis部署
  5. Nginx反向代理
  6. HTTPS自动续期
  7. Cloudflare配置
  8. CI/CD自动发布
  9. 监控告警
  10. 日志系统
  11. 备份恢复
  12. 灰度升级方案

完成后,这套系统即可正式商业运营。

LicenseServer 商业授权系统开发实战文档 v1.0

第九部分(八):生产部署上线方案

本阶段进入:

从开发环境 → 商业生产环境

目标:

部署一套:

  • 高安全
  • 可维护
  • 可扩展
  • 可监控
  • 可备份

的正式 License SaaS 平台。


一、生产环境总体架构

推荐架构:

                         用户

                          |

                          |

                    Cloudflare CDN

                          |

                          |

                    WAF 防火墙

                          |

                          |

                    Nginx Gateway

                          |

          +---------------+----------------+

          |                                |

          |                                |

     Admin Console                  API Server

       Next.js                    ASP.NET Core


                                          |

                         +----------------+---------------+

                         |                                |

                    PostgreSQL                       Redis


                         |

                         |

                    Backup Storage


                         |

                         |

                      Vault

                  密钥管理系统

二、服务器规划建议

小型商业初期

适合:

用户:

< 10万

配置:

API服务器

CPU:
4 Core

RAM:
8GB

SSD:
80GB

运行:

  • ASP.NET API
  • Worker

数据库服务器

CPU:
4 Core

RAM:
16GB

SSD:
200GB

运行:

  • PostgreSQL

Redis

RAM:
2GB

三、推荐云厂商

国际:

  • AWS
  • Azure
  • Google Cloud
  • DigitalOcean
  • Hetzner

国内:

  • 阿里云
  • 腾讯云
  • 华为云

个人商业软件:

推荐:

初期:

Hetzner VPS

+
Cloudflare

成本低。


四、Linux系统选择

推荐:

Ubuntu Server 24.04 LTS

原因:

  • 社区最大
  • Docker支持好
  • 安全更新长期支持

或者:

Debian 13。


五、服务器初始化

登录:

ssh root@server_ip

更新:

apt update

apt upgrade -y

安装基础工具:

apt install \
curl \
git \
vim \
ufw \
fail2ban \
htop \
net-tools

六、安全初始化

禁止root SSH登录

编辑:

vim /etc/ssh/sshd_config

修改:

PermitRootLogin no

创建管理员:

adduser deploy

usermod -aG sudo deploy

重启SSH:

systemctl restart ssh

七、防火墙配置

安装:

ufw enable

允许:

SSH:

ufw allow 22

HTTP:

ufw allow 80

HTTPS:

ufw allow 443

查看:

ufw status

八、安装Docker

官方方式:

curl -fsSL https://get.docker.com \
| sh

检查:

docker version

安装Compose:

docker compose version

九、生产目录规划

推荐:

/opt/license-server/


├── api/

├── admin/

├── worker/


├── postgres/


├── redis/


├── nginx/


├── vault/


├── backups/


└── docker-compose.yml

十、生产Docker Compose

结构:

docker-compose.yml

包含:

  • api
  • admin
  • worker
  • postgres
  • redis
  • nginx

示例:

version: "3.9"


services:


 postgres:

  image:
   postgres:17

  restart:
   always


  environment:

   POSTGRES_DB:
    license


   POSTGRES_USER:
    license_api


   POSTGRES_PASSWORD:
    ${DB_PASSWORD}


  volumes:

   - ./postgres:/var/lib/postgresql/data



 redis:

  image:
   redis:7-alpine


  restart:
   always



 api:

  image:
   company/license-api:latest


  restart:
   always


  depends_on:

   - postgres

   - redis



 worker:

  image:
   company/license-worker:latest


  restart:
   always



 admin:

  image:
   company/license-admin:latest


  restart:
   always



 nginx:

  image:
   nginx:latest


  ports:

   - "80:80"

   - "443:443"

十一、环境变量管理

不要:

appsettings.json

生产:

使用:

.env

例如:

DB_PASSWORD=

JWT_SECRET=

STRIPE_SECRET=

SMTP_PASSWORD=

VAULT_TOKEN=

权限:

chmod 600 .env

十二、PostgreSQL生产配置

参数优化

postgresql.conf:

内存:

例如:

16GB RAM:

shared_buffers = 4GB

effective_cache_size = 12GB

maintenance_work_mem = 1GB

十三、数据库索引

必须建立:

License:

CREATE INDEX idx_license_hash
ON licenses(
license_hash
);

Order:

CREATE INDEX idx_order_no
ON orders(
order_no
);

User:

CREATE INDEX idx_user_email
ON users(
email
);

十四、数据库备份

使用:

pg_dump。

脚本:

#!/bin/bash


DATE=$(date +%Y%m%d)


pg_dump license \
> backup-$DATE.sql

自动:

cron:

每天:

3点。

0 3 * * *
/opt/scripts/backup.sh

十五、备份上传

推荐:

对象存储:

  • AWS S3
  • Cloudflare R2
  • 阿里云OSS

流程:

PostgreSQL



Backup



Encrypt



Cloud Storage

十六、Redis部署

用途:

缓存:

license查询

rate limit

session

queue

生产:

开启密码:

redis.conf:

requirepass StrongPassword

十七、Nginx反向代理

结构:

license.example.com

        |

      Nginx

        |

    localhost:5000

配置:

server {


server_name api.example.com;


location / {


proxy_pass
http://api:8080;


proxy_set_header
Host $host;


proxy_set_header
X-Real-IP $remote_addr;


}


}

十八、HTTPS证书

推荐:

Let’s Encrypt。

安装:

apt install certbot

申请:

certbot --nginx \
-d api.example.com

自动续期:

测试:

certbot renew --dry-run

十九、Cloudflare配置

DNS:

api.example.com

A

server_ip

开启:

Proxy ON

安全:

开启:

  • Bot Fight Mode
  • WAF Rules
  • Rate Limiting

二十、CI/CD自动部署

推荐:

GitHub Actions。

流程:

git push




GitHub Actions




dotnet test




docker build




docker push




服务器pull




docker compose restart

二十一、GitHub Actions示例

name:
Deploy


on:

 push:

  branches:

   - main



jobs:


 build:


  runs-on:
   ubuntu-latest


  steps:


  - uses:
     actions/checkout@v4



  - name:
     Build Docker


    run:

     docker build .

二十二、日志系统

生产不要:

SSH看日志。

推荐:

方案:

Loki + Grafana

结构:

Containers

    |

Promtail

    |

Loki

    |

Grafana

查看:

  • API错误
  • 激活失败
  • 支付失败
  • 登录异常

二十三、监控系统

推荐:

Prometheus + Grafana。

监控:

Server

  • CPU
  • RAM
  • Disk

API

  • 请求数量
  • 延迟
  • 错误率

License

  • 激活次数
  • 失败次数
  • 爆破次数

二十四、告警系统

例如:

邮件:

CPU >90%



发送邮件

License:

5分钟失败激活 >100



安全告警

二十五、应用健康检查

API:

增加:

GET

/health

返回:

{

"status":

"healthy"

}

Docker:

healthcheck:

healthcheck:

 test:

  curl localhost:8080/health

二十六、版本发布策略

不要:

直接覆盖。

采用:

版本:

v1.0.0

v1.0.1

v1.1.0

Docker:

license-api:v1.2.0

二十七、数据库迁移

使用:

EF Core Migration。

发布:

dotnet ef database update

生产:

部署前:

执行:

Migration



Backup



Deploy

二十八、灰度发布

未来:

多服务器:

        Load Balancer


        /        \


    API v1     API v2

先:

10%

用户进入新版。

确认:

错误率。

再:

100%。


二十九、灾难恢复方案

假设:

服务器损坏。

恢复:

新服务器



安装Docker



恢复.env



恢复Vault



恢复数据库



启动服务



验证License

三十、上线Checklist

域名

✅ DNS配置

✅ HTTPS


Server

✅ SSH安全

✅ Firewall

✅ Fail2ban


Docker

✅ 自动启动

✅ 日志限制


Database

✅ 密码

✅ 备份

✅ 索引


License

✅ 签名验证

✅ 私钥保护

✅ 激活限制


Payment

✅ Webhook测试

✅ 自动发货测试


Monitoring

✅ Grafana

✅ Alert


三十一、本阶段完成

模块 状态
服务器架构
Docker生产部署
PostgreSQL部署
Redis部署
Nginx
HTTPS
Cloudflare
CI/CD
监控
备份
灾难恢复

当前系统状态

现在已经达到:

                  Website

                     |

                  Payment

                     |

              License Platform

                     |

              Client SDK

                     |

                User Software

已经具备:

  • 商业销售能力
  • 自动交付能力
  • 安全授权能力
  • 运维能力

下一部分:

第九部分(九):客户端商业发行、防破解与最终交付方案

将重点解决:

  1. Windows/macOS/Linux软件发行
  2. 安装包制作
  3. License SDK集成
  4. .NET应用保护
  5. 防逆向策略
  6. 防Patch方案
  7. 自动更新系统
  8. 崩溃收集
  9. 用户反馈系统
  10. 商业版本管理

这一部分完成后,你的软件就具备完整商业产品发行能力。

LicenseServer 商业授权系统开发实战文档 v1.0

第九部分(九):客户端商业发行、防破解与最终交付方案

本阶段完成:

从“开发完成的软件” → “可以销售给真实用户的商业软件”。

重点:

  • Windows/macOS/Linux 多平台发行
  • 安装包制作
  • 自动更新
  • License SDK集成
  • 软件防篡改
  • 逆向分析防护
  • 崩溃收集
  • 用户反馈
  • 版本管理
  • 商业交付流程

一、商业软件最终架构

最终产品结构:

                  官网

                   |

             下载中心

                   |

        +----------+----------+

        |                     |

   Windows版本          macOS版本

        |                     |

   Installer          DMG / PKG


        |                     |

        +----------+----------+

                   |

             Client App


                   |

            License SDK


                   |

            License Server


                   |

              Activation

二、客户端技术路线建议

你的授权系统使用:

C# + .NET。

客户端推荐:

Windows

推荐:

Avalonia UI

原因:

  • .NET原生
  • 跨平台
  • 商业支持好

结构:

.NET 10

+

Avalonia UI

+

License SDK

macOS

推荐:

Avalonia:

生成:

.app

Linux

支持:

AppImage

.deb

.rpm

三、客户端项目结构

例如:

软件:

MyEditor

结构:

MyEditor/


├── MyEditor.App



├── MyEditor.Core


├── MyEditor.License


├── MyEditor.Update


├── MyEditor.Logging


└── MyEditor.Installer

四、License SDK集成

客户端:

引用:

<ItemGroup>

<ProjectReference

Include="../LicenseSDK"

 />

</ItemGroup>

启动流程:

Application Start


        |

        |

Load License


        |

        |

Verify Signature


        |

        |

Check Expire


        |

        |

Check Feature


        |

        |

Start Software

五、商业版功能控制

不要:

创建多个软件。

例如:

错误:

MyEditor Free.exe

MyEditor Pro.exe

MyEditor Enterprise.exe

容易维护困难。


正确:

一个程序:

MyEditor.exe

通过License控制:

{
features:
[
"export",
"cloud",
"ai"
]
}

例如:

代码:

if(
license.HasFeature("AI")
)
{

EnableAI();

}

六、Feature授权系统

服务器:

定义:

Feature


id

name

description

例如:

Feature 版本
Export PDF Pro
AI Assistant Enterprise
Cloud Sync Enterprise

客户端:

缓存:

FeatureFlags

七、Windows安装包

推荐:

WiX Toolset

微软工业标准。

支持:

  • MSI
  • 企业部署
  • Group Policy

安装:

MyEditorSetup.msi

目录:

Program Files

    |

    MyEditor

八、Windows安装流程

用户:

双击:

Setup.exe

流程:

检测.NET Runtime

        |

安装程序

        |

创建快捷方式

        |

首次启动

        |

输入License

九、macOS发行

格式:

DMG

例如:

MyEditor.dmg

用户:

拖动:

MyEditor.app



Applications

十、macOS签名

苹果要求:

必须:

Code Signing。

使用:

codesign

示例:

codesign \
--deep \
--force \
--sign \
"My Developer ID" \
MyEditor.app

十一、公证(Notarization)

上传:

Apple:

notarytool

流程:

Build



Sign



Upload



Apple Scan



Staple Ticket



Release

十二、Linux发行

支持:

AppImage

优点:

一个文件。

例如:

MyEditor.AppImage

Debian

生成:

myeditor.deb

安装:

sudo dpkg -i myeditor.deb

十三、自动更新系统

商业软件必须有。

不要:

让用户重新下载。


架构:

Client


 |

Check Update


 |

Update Server


 |

Download Package


 |

Verify Signature


 |

Install

十四、Update Server设计

数据库:

增加:

SoftwareVersion


Id

Product

Version

Platform

DownloadUrl

Hash

Signature

ReleaseDate

例如:

{
version:"2.1.0",

platform:"windows",

url:

"https://download.xxx.com/app.exe",

sha256:

"xxxx"

}

十五、更新安全

不能:

直接下载执行。

必须:

验证:

Hash

例如:

SHA256:

download.exe



SHA256



compare

Signature

发布:

私钥签名。

客户端:

公钥验证。


十六、更新流程

查询版本




发现2.0 -> 2.1




下载




验证签名




备份旧版本




替换




启动新版

十七、崩溃收集系统

商业软件必须知道:

用户哪里崩。

推荐:

Sentry

或者:

自建:

Crash Server

收集:

  • Exception
  • OS
  • 软件版本
  • License版本
  • Hardware

不要收集:

  • 用户文件
  • 密码
  • License Key

十八、日志系统

客户端:

分级:

Trace

Debug

Info

Warning

Error

Critical

保存:

Windows:

%LOCALAPPDATA%/MyEditor/logs

macOS:

~/Library/Logs/MyEditor

Linux:

~/.local/share/MyEditor/logs

十九、防破解原则

首先明确:

商业软件不存在绝对防破解。

目标:

提高破解成本。


二十、不要把核心秘密放客户端

错误:

if(key=="ABC123")

unlock

破解者:

直接找到。


正确:

客户端:

只保存:

Public Key

服务器:

保存:

Private Key

二十一、代码混淆

.NET:

推荐:

商业

  • Eazfuscator.NET
  • Babel Obfuscator

免费

  • ConfuserEx

保护:

  • 类名
  • 方法名
  • 字符串
  • 控制流

二十二、字符串保护

不要:

var url=
"https://api.xxx.com";

改:

运行时解密。

例如:

Encrypted String



Decrypt



Use

二十三、防Patch设计

不要:

只有:

bool IsLicensed

改成:

多个验证点:

LicenseValidator


FeatureManager


RuntimeCheck


OnlineCheck

攻击者需要修改多个位置。


二十四、完整性检查

检测:

程序文件修改。

例如:

启动:

Calculate SHA256




Compare



Continue

服务器:

保存:

Official Hash

二十五、反调试

检测:

  • Debugger
  • 调试环境
  • 修改时间

例如:

.NET:

Debugger.IsAttached

注意:

只能作为辅助。


二十六、虚拟机检测

商业软件可以:

检测异常环境。

例如:

  • 大量虚拟设备
  • 异常硬件

但:

不要误伤正常用户。


二十七、License设备管理

用户后台:

显示:

My Devices


Windows PC

MacBook

Linux Server

操作:

Remove Device

二十八、设备解绑策略

例如:

Personal:

每30天:

允许解绑3次。

Professional:

无限。


二十九、用户账户系统

商业软件建议:

不要只靠Key。

采用:

Account

+

License

+

Device

登录:

Email

Password

MFA

三十、最终交付包

最终发布:

Release/


Windows/

 MyEditorSetup.exe


macOS/

 MyEditor.dmg


Linux/

 MyEditor.AppImage


Documentation/

 UserGuide.pdf


License/

 EULA.txt

三十一、软件版本管理

采用:

Semantic Version:

格式:

Major.Minor.Patch


2.5.1

规则:

重大变化:

3.0.0

新增功能:

2.6.0

Bug:

2.5.2

三十二、商业发布流程

完整流程:

开发




自动测试




Build




签名




生成安装包




上传服务器




创建Release




更新官网




通知用户

三十三、最终安全链路

完整保护:

支付


 |

License生成


 |

ECDSA签名


 |

客户端验证


 |

本地加密缓存


 |

Feature控制


 |

运行检查


 |

自动更新验证

三十四、本阶段完成

模块 状态
Windows发行
macOS发行
Linux发行
安装包设计
自动更新
签名验证
崩溃收集
日志系统
防破解策略
版本管理
商业交付流程

当前项目完成度

现在已经达到:

              商业软件生态


                 官网

                  |

               支付系统

                  |

             License Server

                  |

             Admin Console

                  |

              Client SDK

                  |

             用户软件

已经具备:

✅ 商业销售 ✅ 自动交付 ✅ 在线授权 ✅ 离线授权 ✅ 多设备控制 ✅ 自动升级 ✅ 运营管理


下一部分:

第九部分(十):完整源码工程结构 + Docker部署文件 + CI/CD + 商业上线Checklist

这是整个项目文档最后整合阶段,将包含:

  1. 完整Git仓库结构
  2. Backend源码布局
  3. Client SDK源码布局
  4. Admin源码布局
  5. Docker Compose完整文件
  6. Kubernetes扩展方案
  7. GitHub Actions完整CI/CD
  8. 环境变量模板
  9. 生产上线检查表
  10. 后期维护路线图

完成后,你会得到一套完整的:

C#/.NET 商业License SaaS平台工程蓝图。

目前按照我们规划的《LicenseServer 商业授权系统开发实战文档》来看:

第九部分(十)是整个“大章节”的最后一部分。

也就是说:

完成第九部分(十)后,核心设计文档阶段基本完成。

不过,如果目标是达到真正可商业运行的软件授权平台,后面我建议再增加几个“工程落地阶段”,因为前面的内容偏架构设计和核心实现,还需要把它变成一个真正可维护的项目。

完整路线如下:


当前已完成

第九部分(一)~(十)

章节 内容 状态
九(一) License Engine核心实现
九(二) 数据库与后端核心代码
九(三) License核心业务实现
九(四) 客户端SDK完整实现
九(五) 生产级安全加固
九(六) 支付系统+自动发货
九(七) Admin Console后台
九(八) 生产部署上线方案
九(九) 客户端商业发行、防破解
九(十) 源码结构+Docker+CI/CD+上线Checklist 待完成

第九部分(十)完成后

还建议继续:


第十部分:完整项目工程化实现

(推荐继续)

目标:

把架构变成真正代码仓库。

包含:


第十(一):完整Monorepo工程设计

内容:

LicensePlatform/

├── src/


├── License.Api


├── License.Application


├── License.Domain


├── License.Infrastructure


├── License.Worker


├── License.Admin


├── License.Client.SDK


├── License.Client.Demo


├── Tests/


├── Deploy/


└── Docs/

包括:

  • Clean Architecture
  • Domain Driven Design
  • CQRS
  • Repository模式
  • Dependency Injection

第十(二):ASP.NET Core完整Backend实现

包括:

实际代码:

  • Program.cs
  • Middleware
  • JWT认证
  • RBAC
  • EF Core
  • PostgreSQL
  • Redis
  • Background Worker
  • FluentValidation
  • Exception Handler

第十(三):数据库完整实现

包括:

完整:

Users

Roles

Permissions

Products

Plans

Orders

Payments

Licenses

Devices

AuditLogs

Subscriptions

Coupons

提供:

  • Entity
  • DbContext
  • Migration
  • Seed数据

第十(四):License Server源码实现

完整:

包括:

  • Key生成
  • Hash
  • ECDSA签名
  • 激活流程
  • 设备绑定
  • 解绑
  • Heartbeat
  • 离线License

第十(五):Client SDK生产代码

包括:

Windows/macOS/Linux:

  • LicenseManager
  • Storage
  • Crypto
  • DeviceFingerprint
  • UpdateManager

第十(六):Admin Console完整代码

包括:

Next.js:

页面:

Dashboard

Users

Licenses

Orders

Payments

Audit

Settings

组件:

  • Table
  • Form
  • Chart
  • Permission

第十(七):自动更新系统实现

包括:

Server:

Update API

Client:

Update Agent

功能:

  • 检查版本
  • 下载
  • SHA256验证
  • 签名验证
  • 自动安装

第十(八):测试体系

商业软件必须:

包括:

单元测试

xUnit

API测试

WebApplicationFactory

集成测试

Docker Test Containers

安全测试

OWASP


第十(九):商业运维体系

包括:

生产运营:

  • 用户支持
  • License查询
  • 数据分析
  • 错误追踪
  • 安全响应

第十(十):最终商业版本发布

包含:

最终:

LicensePlatform v1.0

├── Server

├── Admin

├── SDK

├── Client Demo

├── Installer

├── Documentation

└── Deployment

后续高级扩展(可选)

如果以后规模扩大,还可以继续:


第十一部分:企业级架构升级

适合:

百万用户。

内容:

  • Kubernetes
  • 微服务拆分
  • 消息队列
  • Kafka
  • RabbitMQ
  • 多区域部署
  • 高可用数据库
  • 灾备

第十二部分:商业SaaS运营体系

内容:

  • 用户增长
  • 产品分析
  • AB测试
  • 邮件营销
  • CRM
  • 客服系统

第十三部分:高级安全攻防

内容:

  • 红队测试
  • 逆向分析
  • Anti-Tamper
  • HSM
  • TPM
  • Secure Boot
  • 代码签名体系

第十四部分:开源级完整项目模板

最终整理成:

GitHub/GitLab项目:

包括:

  • README
  • Architecture Diagram
  • Docker Compose
  • CI/CD
  • Development Guide
  • Production Guide

总结

如果按照完整商业级路线:

阶段 状态
第九部分(一)-(九) 已完成
第九部分(十) 下一步
第十部分 完整源码实现阶段
第十一部分 企业级扩展
第十二部分 商业运营
第十三部分 高级安全

所以回答你的问题:

核心系统设计还剩 1 部分(第九部分十)。

但是如果目标是:

“我要真的开发出来并销售的软件授权平台”

建议继续完成:

第十部分(完整源码工程实现)

因为前面的内容是“架构蓝图”,第十部分才会进入真正的:

  • 文件结构
  • 类设计
  • 数据库代码
  • API代码
  • Docker文件
  • CI/CD脚本
  • 可运行项目

下一步我建议直接开始:

第九部分(十):完整源码工程结构 + Docker部署文件 + CI/CD + 商业上线Checklist

完成后再进入:

第十部分:完整源码实现阶段

这样整个项目会从设计 → 工程 → 商业产品完整闭环。

LicenseServer 商业授权系统开发实战文档 v1.0

第九部分(十):完整源码工程结构 + Docker部署文件 + CI/CD + 商业上线 Checklist

本部分是第九章最后阶段。

目标:

把前面设计的:

  • License Server
  • Client SDK
  • Admin Console
  • Payment System
  • Deployment System

整理成一个真正的软件工程项目。

最终目标:

一个可以 Git 管理、多人开发、自动部署、商业上线的完整项目。


一、最终项目仓库结构(Monorepo)

推荐使用:

GitHub / GitLab Monorepo。

项目名称:

LicensePlatform

完整结构:

LicensePlatform/


├── README.md
├── LICENSE
├── .gitignore
├── docker-compose.yml
├── .env.example



├── src/


├── Server/

│   │
│   ├── License.Api
│   │
│   ├── License.Application
│   │
│   ├── License.Domain
│   │
│   ├── License.Infrastructure
│   │
│   ├── License.Worker
│   │
│   └── License.Migrations



├── Admin/


│   └── license-admin



├── SDK/


│   └── License.Client.SDK



├── Demo/


│   └── Demo.Desktop.App



├── Tests/



├── License.Api.Tests

├── License.Domain.Tests

└── License.Integration.Tests



├── Deploy/



├── docker/



├── nginx/



├── postgres/



├── redis/



└── vault/



├── CI/



└── github-actions



└── Docs/


    ├── Architecture.md

    ├── API.md

    ├── Deployment.md

    └── Security.md

二、后端源码结构

采用:

Clean Architecture

结构:

License.Api

        |

        |

License.Application

        |

        |

License.Domain

        |

        |

License.Infrastructure

三、License.Domain

负责:

核心业务。

包含:

Domain/


Entities/


 License.cs

 User.cs

 Device.cs

 Order.cs


ValueObjects/


 LicenseKey.cs

 DeviceFingerprint.cs


Enums/


 LicenseStatus.cs


Events/


 LicenseActivatedEvent.cs

四、License.Application

业务逻辑。

例如:

Application/


Services/


 LicenseService.cs

 ActivationService.cs

 PaymentService.cs


Interfaces/


 ILicenseRepository.cs

 IPaymentProvider.cs


Commands/


 ActivateLicenseCommand.cs


Queries/


 GetLicenseQuery.cs

五、License.Infrastructure

负责:

外部资源。

包括:

Infrastructure/


Persistence/


 LicenseDbContext.cs


Repositories/


 LicenseRepository.cs


Crypto/


 EcdsaService.cs


Email/


 MailService.cs


Payments/


 StripeProvider.cs


Storage/


 VaultService.cs

六、License.Api

HTTP接口。

结构:

License.Api/


Controllers/


 LicenseController.cs


 PaymentController.cs


 AdminController.cs


Middleware/


 ExceptionMiddleware.cs


Authentication/


 JwtHandler.cs


Program.cs

七、核心API列表

用户接口

注册

POST

/api/auth/register

登录

POST

/api/auth/login

License接口

激活

POST

/api/license/activate

请求:

{

"licenseKey":

"48D0-61CD...",


"fingerprint":

"xxxx"

}

返回:

{

"success":

true,


"expireAt":

"2027-01-01"


}

心跳

POST

/api/license/heartbeat

查询设备

GET

/api/license/devices

八、数据库迁移目录

使用:

EF Core。

结构:

License.Migrations/


Migrations/


20260811_Init.cs

20260812_AddPayment.cs

执行:

开发:

dotnet ef migrations add Init

生产:

dotnet ef database update

九、Admin Console结构

Next.js:

license-admin/


app/


(auth)/login


(admin)/dashboard


(admin)/users


(admin)/licenses


(admin)/orders



components/


ui/


tables/


charts/


lib/


api.ts


hooks/


types/

十、Client SDK结构

License.Client.SDK/


LicenseManager.cs


LicenseClient.cs


LicenseValidator.cs


DeviceFingerprint.cs


LicenseStorage.cs


Crypto/


 EcdsaVerifier.cs

 AesEncryptor.cs


Models/


 LicenseInfo.cs

 ActivationResult.cs

十一、环境变量模板

根目录:

.env.example

内容:

# Database

POSTGRES_DB=license

POSTGRES_USER=license_api

POSTGRES_PASSWORD=password



# JWT

JWT_SECRET=change_me



# Redis

REDIS_PASSWORD=password



# Stripe

STRIPE_SECRET_KEY=

STRIPE_WEBHOOK_SECRET=



# SMTP

SMTP_HOST=

SMTP_USER=

SMTP_PASSWORD=



# Vault

VAULT_ADDR=

VAULT_TOKEN=



# Domain

API_DOMAIN=

ADMIN_DOMAIN=

十二、Docker生产部署结构

最终:

Docker


├── nginx

├── api

├── admin

├── worker

├── postgres

├── redis

└── vault

十三、生产docker-compose.yml

示例:

services:


 postgres:

  image: postgres:17


  restart: always


  environment:

   POSTGRES_DB:
    ${POSTGRES_DB}


   POSTGRES_USER:
    ${POSTGRES_USER}


   POSTGRES_PASSWORD:
    ${POSTGRES_PASSWORD}


  volumes:

   - postgres_data:/var/lib/postgresql/data



 redis:


  image:
   redis:7-alpine


  restart:
   always



 api:


  image:
   company/license-api:${VERSION}


  restart:
   always


  depends_on:

   - postgres

   - redis



 worker:


  image:
   company/license-worker:${VERSION}



 admin:


  image:
   company/license-admin:${VERSION}



 nginx:


  image:
   nginx:latest


  ports:

   - "80:80"

   - "443:443"


volumes:


 postgres_data:

十四、Docker镜像设计

API Dockerfile

FROM mcr.microsoft.com/dotnet/aspnet:10.0


WORKDIR /app


COPY publish .


ENTRYPOINT [

"dotnet",

"License.Api.dll"

]

Admin Dockerfile

FROM node:24-alpine


WORKDIR /app


COPY . .


RUN npm install


RUN npm run build


CMD [

"npm",

"start"

]

十五、GitHub Actions CI/CD

目录:

.github/workflows/


build.yml

deploy.yml

十六、自动测试流程

提交代码:

Git Push




GitHub Actions




Restore




Build




Test




Docker Build




Security Scan




Deploy

十七、Backend CI示例

name:
backend-build


on:

 push:

  branches:

   - main



jobs:


 build:


  runs-on:
   ubuntu-latest


  steps:


  - uses:
      actions/checkout@v4



  - name:
      dotnet test


    run:

      dotnet test



  - name:
      docker build


    run:

      docker build .

十八、安全扫描流程

加入:

Trivy

扫描:

Docker镜像。

trivy image license-api

Dependabot

检查:

  • NuGet漏洞
  • npm漏洞

十九、发布流程

正式版本:

Developer





Pull Request





Review





Merge





CI Build





Create Version





Docker Push





Production Deploy

二十、版本管理

采用:

Semantic Version。

例如:

v1.0.0

规则:

Major

重大变化:

2.0.0

Minor

新增功能:

1.5.0

Patch

Bug修复:

1.5.1

二十一、生产上线 Checklist

域名

✅ DNS配置

✅ SSL证书

✅ Cloudflare开启


服务器

✅ Ubuntu/Debian更新

✅ SSH安全

✅ 防火墙

✅ Fail2Ban


Docker

✅ 自动启动

✅ 日志限制

✅ 镜像版本固定


数据库

✅ 强密码

✅ 自动备份

✅ 恢复测试


License

✅ ECDSA签名

✅ 私钥Vault保存

✅ License Hash保存


支付

✅ Stripe测试

✅ Webhook验证

✅ 自动发货测试


客户端

✅ Windows安装测试

✅ macOS签名

✅ Linux AppImage测试


安全

✅ OWASP扫描

✅ API限流

✅ 管理员MFA


二十二、上线前测试矩阵

Windows

测试:

  • Windows 10
  • Windows 11

macOS

测试:

  • Intel Mac
  • Apple Silicon

Linux

测试:

  • Ubuntu
  • Debian
  • Fedora

二十三、灾备检查

模拟:

服务器删除。

验证:

重新部署




恢复数据库




恢复Vault




恢复License




用户继续激活

二十四、最终商业版本结构

最终交付:

LicensePlatform v1.0


├── Backend

├── Admin Console

├── Client SDK

├── Demo Application

├── Docker Deployment

├── CI/CD

├── Documentation

└── Security Policy

二十五、第九部分全部完成

至此:

第九部分(一)~(十)全部完成

整个商业License系统已经包含:

模块 完成
授权引擎
客户端SDK
支付系统
自动发货
后台管理
安全体系
生产部署
CI/CD
商业发行

下一阶段:第十部分(完整源码工程实现阶段)

这一部分会从“设计文档”进入真正开发:

将开始写:

第十(一):Monorepo完整初始化 + .NET Solution + Next.js工程创建

内容:

  • Git初始化
  • Solution创建
  • 项目引用关系
  • NuGet配置
  • Docker开发环境
  • PostgreSQL初始化
  • EF Core配置
  • 第一批真实代码

也就是说:

前面约 80% 是架构设计

第十部分开始:

真正写代码,逐文件实现。

完成第十部分后,你将拥有一个可以直接开发的商业License平台源码。

LicenseServer 商业授权系统开发实战文档 v1.0

第十部分:完整源码工程实现阶段

第十(一):Monorepo 初始化 + .NET Solution + Next.js 工程创建

从本部分开始,我们进入真实工程代码阶段

目标:

创建一个可以长期维护的商业级代码仓库:

  • Backend(ASP.NET Core)
  • Admin Console(Next.js)
  • Client SDK(.NET)
  • Worker Service
  • Database
  • Docker开发环境
  • CI/CD基础

一、开发环境统一规范

由于你需要:

  • macOS开发
  • Windows开发
  • Linux开发

所以必须统一工具链。

推荐:

组件 版本
.NET 10 LTS
C# 14
Node.js 24 LTS
Bun 1.2+
TypeScript 5.9+(TS 7正式稳定后再升级)
PostgreSQL 17
Redis 7
Docker 最新稳定版
Git 2.45+

二、为什么不建议现在直接使用 TypeScript 7.0?

你之前提到想使用:

TypeScript 7.0

建议:

生产项目不要第一时间追最新大版本。

原因:

TypeScript升级影响:

  • Next.js
  • ESLint
  • Vite
  • Turbopack
  • 类型声明

商业项目建议:

当前:

TypeScript 5.9.x

等:

Next.js
React
VSCode
主要生态

全部验证后:

再升级:

TypeScript 7.x

三、为什么选择 Bun?

你的问题:

Node.js能不能用Bun替代?

答案:

可以。

但是建议:

开发环境

使用:

Bun

生产环境

Admin Console:

推荐:

Node.js 24 LTS

原因:

商业稳定优先。


推荐组合:

开发:

Bun



Next.js



TypeScript

生产:

Node.js



Next.js Standalone



Docker

四、创建项目根目录

例如:

Linux/macOS:

mkdir LicensePlatform

cd LicensePlatform

git init

Windows:

PowerShell:

mkdir LicensePlatform

cd LicensePlatform

git init

五、初始化目录

创建:

mkdir src
mkdir deploy
mkdir docs
mkdir tests

最终:

LicensePlatform

├── src

├── deploy

├── docs

├── tests

└── README.md

六、创建.NET Solution

进入:

cd src

创建:

dotnet new sln \
-n LicensePlatform

生成:

LicensePlatform.sln

七、创建Backend项目

进入:

mkdir Server

cd Server

1. API项目

dotnet new webapi \
-n License.Api

2. Domain项目

dotnet new classlib \
-n License.Domain

3. Application项目

dotnet new classlib \
-n License.Application

4. Infrastructure项目

dotnet new classlib \
-n License.Infrastructure

5. Worker项目

dotnet new worker \
-n License.Worker

八、加入Solution

返回:

cd ..

执行:

dotnet sln add \
Server/**/*.csproj

查看:

dotnet sln list

应该:

License.Api

License.Domain

License.Application

License.Infrastructure

License.Worker

九、项目引用关系设计

Clean Architecture:

             API

              |

              |

        Application

              |

              |

          Domain


Infrastructure

              |

              |

        Database

规则:

Domain

不能引用任何东西。


Application

引用:

Domain

Infrastructure

引用:

Application

Domain

API

引用:

Application

Infrastructure

执行:

Application:

dotnet add \
License.Application.csproj \
reference \
../License.Domain/License.Domain.csproj

Infrastructure:

dotnet add \
License.Infrastructure.csproj \
reference \
../License.Application/License.Application.csproj

API:

dotnet add \
License.Api.csproj \
reference \
../License.Application/License.Application.csproj


dotnet add \
License.Api.csproj \
reference \
../License.Infrastructure/License.Infrastructure.csproj

十、创建Client SDK项目

返回:

cd ../../

创建:

mkdir SDK

cd SDK

执行:

dotnet new classlib \
-n License.Client.SDK

加入:

cd ../..

dotnet sln src/LicensePlatform.sln add \
src/SDK/License.Client.SDK/License.Client.SDK.csproj

十一、创建Demo客户端

用于测试授权。

mkdir Demo

cd Demo


dotnet new console \
-n License.Demo.Client

加入:

dotnet sln add \
Demo/License.Demo.Client/*.csproj

十二、创建Admin Console

返回根目录:

cd LicensePlatform

mkdir src/Admin

cd src/Admin

使用Bun:

bun create next-app license-admin

选择:

✔ TypeScript

✔ ESLint

✔ Tailwind

✔ App Router

✔ src directory

✔ Turbopack

进入:

cd license-admin

测试:

bun dev

访问:

http://localhost:3000

十三、Admin依赖安装

安装:

bun add axios

bun add \
@tanstack/react-query

bun add \
zod

bun add \
react-hook-form

UI:

bunx shadcn@latest init

安装组件:

bunx shadcn@latest add \
button \
card \
table \
dialog \
form

十四、最终源码结构

现在:

LicensePlatform/


src/


├── Server/



├── License.Api


├── License.Domain


├── License.Application


├── License.Infrastructure


└── License.Worker



├── SDK/



└── License.Client.SDK



├── Demo/



└── License.Demo.Client



└── Admin/


    └── license-admin



deploy/

docs/

tests/

十五、添加.gitignore

根目录:

dotnet new gitignore

追加:

node_modules/

.next/

.env

.env.*

bin/

obj/

.idea/

.vscode/

十六、添加Directory.Build.props

根目录:

创建:

Directory.Build.props

内容:

<Project>


<PropertyGroup>


<Nullable>
enable
</Nullable>


<ImplicitUsings>
enable
</ImplicitUsings>


<TreatWarningsAsErrors>
false
</TreatWarningsAsErrors>


<LangVersion>
latest
</LangVersion>


</PropertyGroup>


</Project>

十七、统一NuGet版本管理

创建:

Directory.Packages.props

例如:

<Project>


<PropertyGroup>


<ManagePackageVersionsCentrally>

true

</ManagePackageVersionsCentrally>


</PropertyGroup>


<ItemGroup>


<PackageVersion

Include="Microsoft.EntityFrameworkCore"

Version="10.0.0"

/>


</ItemGroup>


</Project>

十八、第一次完整编译

根目录:

dotnet build

Next:

cd src/Admin/license-admin

bun run build

十九、本阶段完成

完成内容:

项目 状态
Monorepo
.NET Solution
Clean Architecture结构
API项目
Domain项目
Infrastructure项目
Worker项目
Client SDK项目
Next.js Admin项目
Bun开发环境
跨平台基础

下一章节

第十(二):ASP.NET Core Backend 核心代码实现

将开始真正写:

  • Program.cs
  • Dependency Injection
  • EF Core
  • PostgreSQL连接
  • Redis配置
  • JWT认证
  • 用户系统
  • License API
  • Middleware
  • 全局异常处理

也就是开始进入:

第一行商业系统后端代码实现阶段。

LicenseServer 商业授权系统开发实战文档 v1.0

第十部分:完整源码工程实现阶段

第十(二):ASP.NET Core Backend 核心代码实现

本阶段开始进入真正 Backend 编码阶段。

目标:

完成:

  • ASP.NET Core API基础架构
  • Clean Architecture启动
  • Dependency Injection
  • PostgreSQL数据库连接
  • Entity Framework Core
  • Redis缓存
  • JWT认证
  • 全局异常处理
  • API版本控制
  • Swagger
  • 健康检查

最终:

Client

 |

HTTPS

 |

License.Api

 |

Application Layer

 |

Infrastructure

 |

PostgreSQL + Redis

一、Backend最终结构

完善:

License.Api

├── Controllers


├── AuthController.cs

├── LicenseController.cs

├── HealthController.cs


├── Middleware


└── ExceptionMiddleware.cs


├── Extensions


├── ServiceExtensions.cs

├── SwaggerExtensions.cs


├── Configuration


├── JwtSettings.cs


└── Program.cs



License.Application


├── Interfaces

├── Services

├── DTOs

├── Validators



License.Infrastructure


├── Persistence

├── Repositories

├── Cache

├── Security

二、安装Backend依赖

进入:

cd src/Server

License.Api

dotnet add License.Api package \
Microsoft.AspNetCore.Authentication.JwtBearer

Swagger:

dotnet add License.Api package \
Swashbuckle.AspNetCore

Infrastructure

EF Core:

dotnet add License.Infrastructure package \
Microsoft.EntityFrameworkCore

dotnet add License.Infrastructure package \
Npgsql.EntityFrameworkCore.PostgreSQL

Redis:

dotnet add License.Infrastructure package \
StackExchange.Redis

Application

验证:

dotnet add License.Application package \
FluentValidation

三、配置文件设计

appsettings.json

路径:

License.Api/appsettings.json

内容:

{
  "ConnectionStrings": {

    "DefaultConnection":
    "Host=localhost;Port=5432;Database=license;Username=license;Password=password"

  },


  "Redis": {

    "Connection":
    "localhost:6379"

  },


  "Jwt": {

    "Issuer":
    "LicenseServer",

    "Audience":
    "LicenseClient",

    "Secret":
    "CHANGE_ME"

  },


  "Logging": {

    "LogLevel": {

      "Default":
      "Information"

    }

  }

}

四、创建Domain实体

进入:

License.Domain

创建:

Entities/User.cs

代码:

namespace License.Domain.Entities;


public class User
{

    public Guid Id { get; set; }


    public string Email { get; set; } = "";


    public string PasswordHash { get; set; } = "";


    public DateTime CreatedAt { get; set; }

        =
        DateTime.UtcNow;


}

五、License实体

创建:

Entities/License.cs

代码:

namespace License.Domain.Entities;


public class License
{

    public Guid Id { get; set; }


    public string LicenseKeyHash { get; set; } = "";


    public Guid UserId { get; set; }


    public int MaxDevices { get; set; }


    public DateTime ExpireAt { get; set; }


    public bool Enabled { get; set; }


}

六、创建DbContext

路径:

License.Infrastructure/Persistence

创建:

LicenseDbContext.cs

代码:

using Microsoft.EntityFrameworkCore;
using License.Domain.Entities;


namespace License.Infrastructure.Persistence;


public class LicenseDbContext
    :
    DbContext
{


public LicenseDbContext(
DbContextOptions options)
:
base(options)
{

}



public DbSet<User> Users => Set<User>();


public DbSet<License> Licenses => Set<License>();


}

七、Infrastructure依赖注入

创建:

DependencyInjection.cs

代码:

using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;


namespace License.Infrastructure;


public static class DependencyInjection
{


public static IServiceCollection AddInfrastructure(
this IServiceCollection services,
IConfiguration config)
{


services.AddDbContext<LicenseDbContext>(
options =>
{

options.UseNpgsql(
config.GetConnectionString(
"DefaultConnection"));

});


return services;


}


}

八、Application层服务接口

创建:

Interfaces/ILicenseService.cs

代码:

using License.Domain.Entities;


namespace License.Application.Interfaces;


public interface ILicenseService
{


Task<License?>
GetLicenseAsync(
string key);


}

九、License Service实现

创建:

Services/LicenseService.cs

代码:

using License.Application.Interfaces;
using License.Infrastructure.Persistence;
using Microsoft.EntityFrameworkCore;


namespace License.Application.Services;


public class LicenseService
:
ILicenseService
{


private readonly LicenseDbContext _db;



public LicenseService(
LicenseDbContext db)
{

_db=db;

}



public async Task<Domain.Entities.License?>
GetLicenseAsync(
string key)
{


return await _db.Licenses
.FirstOrDefaultAsync(
x=>x.LicenseKeyHash==key);


}


}

十、Application依赖注入

创建:

DependencyInjection.cs

代码:

using Microsoft.Extensions.DependencyInjection;
using License.Application.Interfaces;
using License.Application.Services;


namespace License.Application;


public static class DependencyInjection
{


public static IServiceCollection AddApplication(
this IServiceCollection services)
{


services.AddScoped
<
ILicenseService,
LicenseService
>();


return services;


}


}

十一、Program.cs核心配置

修改:

License.Api/Program.cs

代码:

using License.Application;
using License.Infrastructure;


var builder =
WebApplication.CreateBuilder(args);



builder.Services
.AddApplication();



builder.Services
.AddInfrastructure(
builder.Configuration);



builder.Services
.AddControllers();



builder.Services
.AddEndpointsApiExplorer();


builder.Services
.AddSwaggerGen();



var app =
builder.Build();



if(app.Environment.IsDevelopment())
{

app.UseSwagger();

app.UseSwaggerUI();

}



app.UseHttpsRedirection();



app.MapControllers();



app.Run();

十二、创建健康检查

安装:

无需额外包。

Program加入:

builder.Services
.AddHealthChecks();

下面:

app.MapHealthChecks(
"/health");

测试:

浏览:

https://localhost:7000/health

返回:

Healthy

十三、创建License Controller

路径:

Controllers/LicenseController.cs

代码:

using Microsoft.AspNetCore.Mvc;
using License.Application.Interfaces;


namespace License.Api.Controllers;



[ApiController]

[Route("api/license")]

public class LicenseController
:
ControllerBase

{


private readonly ILicenseService _service;



public LicenseController(
ILicenseService service)
{

_service=service;

}



[HttpGet("{key}")]

public async Task<IActionResult>
Get(
string key)
{


var license =
await _service
.GetLicenseAsync(key);



if(license==null)

return NotFound();



return Ok(license);


}


}

十四、运行测试

启动:

dotnet run \
--project License.Api

访问:

GET

/api/license/test

返回:

{
"id":"xxx",
"enabled":true
}

十五、添加JWT认证框架

安装:

已经:

Microsoft.AspNetCore.Authentication.JwtBearer

Program增加:

builder.Services
.AddAuthentication()
.AddJwtBearer();

增加:

app.UseAuthentication();

app.UseAuthorization();

十六、添加全局异常处理中间件

创建:

Middleware/ExceptionMiddleware.cs

代码:

public class ExceptionMiddleware
{


private readonly RequestDelegate _next;


public ExceptionMiddleware(
RequestDelegate next)
{

_next=next;

}


public async Task Invoke(
HttpContext context)
{

try
{

await _next(context);

}

catch(Exception ex)
{

context.Response.StatusCode=500;


await context.Response.WriteAsync(
"Internal Server Error");


}


}


}

注册:

Program:

app.UseMiddleware
<ExceptionMiddleware>();

十七、本阶段完成

完成:

模块 状态
ASP.NET Core基础
Clean Architecture
EF Core
PostgreSQL连接
Redis准备
DI系统
License API
Health Check
Swagger
异常处理中间件

下一章节

第十(三):数据库完整实现 + EF Core Migration + Repository模式

下一步将实现:

  1. 完整数据库模型

包括:

Users
Roles
Permissions
Products
Plans
Orders
Payments
Licenses
Devices
AuditLogs
Subscriptions
Coupons
  1. Entity关系设计
  2. EF Core Fluent API配置
  3. Migration生成
  4. Seed初始化管理员
  5. Repository + UnitOfWork

完成后,Backend将从“框架”进入真正商业业务数据库层。

LicenseServer 商业授权系统开发实战文档 v1.0

第十部分:完整源码工程实现阶段

第十(三):数据库完整实现 + EF Core Migration + Repository模式

本阶段进入:

商业授权平台核心数据层实现。

目标:

完成:

  • PostgreSQL数据库设计
  • Entity Framework Core实体模型
  • Fluent API关系配置
  • 数据库Migration
  • 初始化数据Seed
  • Repository模式
  • Unit Of Work
  • 数据访问规范

最终数据库架构:

                 Users

                   |

        +----------+-----------+

        |                      |

    Licenses               Orders

        |

    Devices


Products

    |

Plans


Payments


AuditLogs


Roles

    |

Permissions

一、数据库技术选型

采用:

组件 版本
数据库 PostgreSQL 17
ORM EF Core 10
驱动 Npgsql
迁移 EF Core Migration
缓存 Redis 7

原因:

PostgreSQL适合:

  • SaaS系统
  • 高并发查询
  • JSON数据
  • 索引能力
  • 数据分析

二、完整数据库模型

最终表:

Users
|
├── Roles
|
├── Licenses
|
├── Orders
|
├── Payments
|
├── Devices
|
├── AuditLogs


Products

|
Plans


Subscriptions


Coupons


Permissions

三、基础实体设计

目录:

License.Domain

└── Entities

1. User实体

文件:

Entities/User.cs
namespace License.Domain.Entities;


public class User
{

    public Guid Id {get;set;}


    public string Email {get;set;} = "";


    public string PasswordHash {get;set;} = "";


    public bool EmailVerified {get;set;}


    public DateTime CreatedAt {get;set;}
        = DateTime.UtcNow;


    public Guid? RoleId {get;set;}


    public Role? Role {get;set;}


    public ICollection<License>
        Licenses {get;set;}
        = new List<License>();


}

四、Role权限模型

Role

public class Role
{

public Guid Id {get;set;}


public string Name {get;set;}=""


public ICollection<User>
Users {get;set;}
=new List<User>();


public ICollection<RolePermission>
Permissions {get;set;}
=new List<RolePermission>();


}

Permission

public class Permission
{

public Guid Id {get;set;}


public string Code {get;set;}=""


public string Description {get;set;}=""


}

RolePermission

多对多关系:

public class RolePermission
{

public Guid RoleId {get;set;}

public Role Role {get;set;}=null!;



public Guid PermissionId {get;set;}

public Permission Permission {get;set;}=null!;


}

五、Product产品模型

对应:

软件产品。

例如:

PhotoManager Pro
VideoTool Enterprise

实体:

public class Product
{


public Guid Id {get;set;}


public string Name {get;set;}="";


public string Code {get;set;}="";


public ICollection<Plan>
Plans {get;set;}
=new();


}

六、Plan套餐模型

例如:

Personal

Professional

Enterprise

代码:

public class Plan
{


public Guid Id {get;set;}


public Guid ProductId {get;set;}


public Product Product {get;set;}=null!;


public string Name {get;set;}="";


public decimal Price {get;set;}


public int MaxDevices {get;set;}


public int ValidDays {get;set;}


}

七、License授权模型

这是核心表。

public class License
{


public Guid Id {get;set;}


public string LicenseKeyHash {get;set;}="";


public Guid UserId {get;set;}


public User User {get;set;}=null!;


public Guid PlanId {get;set;}


public Plan Plan {get;set;}=null!;


public int MaxDevices {get;set;}


public DateTime ExpireAt {get;set;}


public bool Enabled {get;set;}


public DateTime CreatedAt {get;set;}
=DateTime.UtcNow;


public ICollection<Device>
Devices {get;set;}
=new();


}

八、Device设备绑定模型

用于:

限制:

1台 / 3台 / 5台。

public class Device
{


public Guid Id {get;set;}


public Guid LicenseId {get;set;}


public License License {get;set;}=null!;


public string Fingerprint {get;set;}="";


public string Platform {get;set;}="";


public string DeviceName {get;set;}="";


public DateTime LastHeartbeat {get;set;}


public DateTime CreatedAt {get;set;}
=DateTime.UtcNow;


}

九、订单模型

public class Order
{


public Guid Id {get;set;}


public string OrderNo {get;set;}="";


public Guid UserId {get;set;}


public decimal Amount {get;set;}


public string Currency {get;set;}="USD";


public string Status {get;set;}="Pending";


public DateTime CreatedAt {get;set;}
=DateTime.UtcNow;


}

十、Payment支付记录

public class Payment
{


public Guid Id {get;set;}


public Guid OrderId {get;set;}


public string Provider {get;set;}="Stripe";


public string TransactionId {get;set;}="";


public string Status {get;set;}="";


public DateTime CreatedAt {get;set;}


}

十一、AuditLog审计日志

商业后台必须有。

public class AuditLog
{


public Guid Id {get;set;}


public Guid? UserId {get;set;}


public string Action {get;set;}="";


public string IpAddress {get;set;}="";


public string Detail {get;set;}="";


public DateTime CreatedAt {get;set;}
=DateTime.UtcNow;


}

十二、DbContext完整实现

文件:

License.Infrastructure/Persistence/LicenseDbContext.cs
using Microsoft.EntityFrameworkCore;
using License.Domain.Entities;


public class LicenseDbContext
:
DbContext
{


public LicenseDbContext(
DbContextOptions options)
:base(options)
{

}



public DbSet<User> Users=>Set<User>();

public DbSet<Role> Roles=>Set<Role>();

public DbSet<Permission> Permissions=>Set<Permission>();

public DbSet<Product> Products=>Set<Product>();

public DbSet<Plan> Plans=>Set<Plan>();

public DbSet<License> Licenses=>Set<License>();

public DbSet<Device> Devices=>Set<Device>();

public DbSet<Order> Orders=>Set<Order>();

public DbSet<Payment> Payments=>Set<Payment>();

public DbSet<AuditLog> AuditLogs=>Set<AuditLog>();



protected override void OnModelCreating(
ModelBuilder builder)
{


base.OnModelCreating(builder);



}

}

十三、Fluent API配置

创建:

Configurations

例如:

UserConfiguration.cs

代码:

using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;


public class UserConfiguration
:
IEntityTypeConfiguration<User>
{


public void Configure(
EntityTypeBuilder<User> builder)
{


builder
.HasIndex(x=>x.Email)
.IsUnique();



builder
.Property(x=>x.Email)
.HasMaxLength(256);



}


}

十四、注册所有配置

DbContext:

加入:

protected override void OnModelCreating(
ModelBuilder builder)
{


builder.ApplyConfigurationsFromAssembly(
typeof(LicenseDbContext)
.Assembly);


}

十五、安装EF Migration工具

全局:

dotnet tool install \
--global dotnet-ef

检查:

dotnet ef --version

十六、创建第一次Migration

进入:

cd src/Server

执行:

dotnet ef migrations add InitialCreate \
-p License.Infrastructure \
-s License.Api

生成:

Migrations/

20260811_InitialCreate.cs

十七、更新数据库

开发环境:

dotnet ef database update \
-p License.Infrastructure \
-s License.Api

数据库:

生成:

Users

Roles

Licenses

Devices

Orders

Payments

十八、Repository模式

为什么需要?

不要:

Controller直接操作DbContext。

错误:

_db.Users.FirstAsync();

正确:

Controller



Service



Repository



DbContext

十九、Repository接口

Application:

创建:

Interfaces/IRepository.cs
public interface IRepository<T>
where T:class
{


Task<T?> GetAsync(Guid id);



Task<List<T>> GetAllAsync();



Task AddAsync(T entity);



void Remove(T entity);


}

二十、Repository实现

Infrastructure:

public class Repository<T>
:
IRepository<T>
where T:class
{


private readonly LicenseDbContext _db;



public Repository(
LicenseDbContext db)
{

_db=db;

}



public async Task<T?> GetAsync(
Guid id)
{


return await _db.Set<T>()
.FindAsync(id);

}



public async Task<List<T>>
GetAllAsync()
{


return await _db.Set<T>()
.ToListAsync();

}



public async Task AddAsync(
T entity)
{


await _db.Set<T>()
.AddAsync(entity);


}


public void Remove(
T entity)
{


_db.Remove(entity);


}


}

二十一、Unit Of Work

接口:

public interface IUnitOfWork
{


IRepository<User> Users {get;}


IRepository<License> Licenses {get;}


Task<int> SaveAsync();


}

二十二、实现UnitOfWork

public class UnitOfWork
:
IUnitOfWork
{


private readonly LicenseDbContext _db;



public IRepository<User> Users {get;}


public IRepository<License> Licenses {get;}



public UnitOfWork(
LicenseDbContext db)
{

_db=db;


Users=
new Repository<User>(db);


Licenses=
new Repository<License>(db);

}



public Task<int>
SaveAsync()
{

return _db.SaveChangesAsync();

}


}

二十三、注册DI

Infrastructure:

services.AddScoped(
typeof(IRepository<>),
typeof(Repository<>)
);


services.AddScoped
<IUnitOfWork,
UnitOfWork>();

二十四、数据库Seed初始化

创建:

DatabaseSeeder.cs

初始化:

默认管理员:

admin@example.com

Role:

SuperAdmin

二十五、本阶段完成

模块 状态
完整数据库模型
EF Core实体
Fluent API
Migration
PostgreSQL结构
Repository
UnitOfWork
RBAC基础
Seed设计

下一章节

第十(四):License Server源码实现

下一部分开始实现真正核心:

License Engine

包括:

  1. License Key生成算法

例如:

48D0-61CD-35FE...
  1. ECDSA数字签名
  2. Private Key保护
  3. Public Key客户端验证
  4. 激活流程
  5. 设备指纹算法
  6. 在线激活API
  7. 离线License文件
  8. Heartbeat机制
  9. 防重放攻击

完成后,这套系统才真正拥有商业软件授权能力。

LicenseServer 商业授权系统开发实战文档 v1.0

第十部分:完整源码工程实现阶段

第十(四):License Server 源码实现

本阶段实现整个系统最核心模块:

License Engine(授权引擎)

这是商业软件授权系统的核心竞争力。

目标:

实现:

  • License Key生成
  • License数据签名
  • 激活验证
  • 设备绑定
  • 多设备限制
  • 在线授权
  • 离线授权
  • Heartbeat检测
  • 防重放攻击
  • 防篡改验证

最终流程:

                 Admin Console

                       |

                       |

              Create License

                       |

                       |

              License Server

                       |

              +--------+---------+

              |                  |

          Database          Private Key


                                   |

                                   |

                             Signed License


                                   |

                                   |

                              Client SDK


                                   |

                              Public Key Verify

一、License设计原则

商业授权不能简单:

Key = ABC123

因为:

攻击者可以:

  • 修改客户端
  • 破解判断逻辑
  • 生成假Key

采用:

非对称密码体系

服务器:

保存:

Private Key

负责:

签名。

客户端:

保存:

Public Key

负责:

验证。

关系:

Private Key

       |

       |

    Signature

       |

       |

License Data


       |

       |

 Public Key Verify

二、License数据结构设计

创建:

License.Domain/Models/LicensePayload.cs

代码:

namespace License.Domain.Models;


public class LicensePayload
{


public string LicenseId {get;set;}="";


public string Product {get;set;}="";


public string Plan {get;set;}="";


public string UserEmail {get;set;}="";


public int MaxDevices {get;set;}


public DateTime IssuedAt {get;set;}


public DateTime ExpireAt {get;set;}


public string[] Features {get;set;}=[];


}

三、最终License格式

用户看到:

48D0-61CD-35FE-9C9B-5358-3725-D644-1A18

但是内部:

不是直接保存。

实际:

{
"id":
"7d8a....",

"product":
"MyEditor",

"plan":
"Professional",

"maxDevices":
3,

"expire":
"2027-01-01",

"signature":
"MEUCIQ..."
}

四、License Key生成

不要使用:

Random()

原因:

可预测。

使用:

Cryptographically Secure Random

代码:

创建:

License.Infrastructure/Security/LicenseKeyGenerator.cs
using System.Security.Cryptography;


public class LicenseKeyGenerator
{


public string Generate()
{


byte[] buffer =
RandomNumberGenerator
.GetBytes(16);



string key =
Convert.ToHexString(buffer);



return Format(key);


}



private string Format(
string input)
{


return string.Join(
"-",

Enumerable.Range(0, input.Length / 4)

.Select(
i=>input.Substring(i*4,4))

);


}


}

生成:

例如:

A81F-92CC-17DA-4B55-9F31-88AA-92F1-22DE

五、License Hash存储

数据库:

不要保存明文Key。

错误:

LicenseKey

48D0-61CD...

正确:

保存:

SHA256(Key)

原因:

数据库泄露时:

攻击者无法直接使用。


创建:

LicenseHasher.cs

代码:

using System.Security.Cryptography;
using System.Text;


public class LicenseHasher
{


public string Hash(
string key)
{


using var sha =
SHA256.Create();


byte[] data =
Encoding.UTF8
.GetBytes(key);



return Convert
.ToHexString(
sha.ComputeHash(data));

}


}

六、ECDSA密钥生成

算法:

ECDSA P-256

生成:

工具:

openssl ecparam \
-name prime256v1 \
-genkey \
-noout \
-out private.pem

导出公钥:

openssl ec \
-in private.pem \
-pubout \
-out public.pem

最终:

服务器:

private.pem

客户端:

public.pem

七、License签名服务

创建:

Security/LicenseSigner.cs

代码:

using System.Security.Cryptography;
using System.Text;
using System.Text.Json;



public class LicenseSigner
{


private readonly ECDsa _ecdsa;



public LicenseSigner(
ECDsa ecdsa)
{

_ecdsa=ecdsa;

}



public string Sign(
LicensePayload payload)
{


string json =
JsonSerializer.Serialize(payload);



byte[] data =
Encoding.UTF8
.GetBytes(json);



byte[] signature =
_ecdsa.SignData(
data,
HashAlgorithmName.SHA256);



return Convert
.ToBase64String(
signature);


}


}

八、License验证

客户端:

使用:

Public Key。

代码:

public bool Verify(
string json,
string signature)
{


byte[] data =
Encoding.UTF8.GetBytes(json);



byte[] sign =
Convert.FromBase64String(
signature);



return _ecdsa.VerifyData(
data,
sign,
HashAlgorithmName.SHA256);

}

九、License创建流程

Admin点击:

Create License

流程:

Admin

 |

 |

POST /admin/license/create


 |

 |

Generate Key


 |

 |

Create Payload


 |

 |

Sign Payload


 |

 |

Save Hash


 |

 |

Return Key

十、创建License Service

Application:

创建:

Services/LicenseIssuerService.cs

代码:

public class LicenseIssuerService
{


private readonly LicenseKeyGenerator _generator;


private readonly LicenseSigner _signer;



public async Task<string>
CreateAsync(
LicensePayload payload)
{


var key =
_generator.Generate();



var signature =
_signer.Sign(payload);



return key;


}

}

十一、激活API设计

客户端首次启动:

发送:

POST

/api/license/activate

请求:

{

"licenseKey":
"48D0-61CD...",


"deviceFingerprint":
"xxxx"


}

十二、Activation Service

创建:

ActivationService.cs

逻辑:

1. Hash License Key

2. 查询数据库

3. 判断是否存在

4. 判断是否过期

5. 查询设备数量

6. 新增设备

7. 返回License Payload

代码框架:

public async Task<Result>
Activate(
ActivateRequest request)
{


var hash =
_hasher.Hash(
request.LicenseKey);



var license =
await repo.Find(hash);



if(license==null)

return Failed();



if(
license.Devices.Count
>=
license.MaxDevices)

return DeviceLimit();



AddDevice();



return Success();


}

十三、设备指纹算法

目标:

识别:

同一电脑。

不能:

只使用MAC地址。

因为:

容易变化。


组合:

Windows:

MachineGuid

CPU ID

Disk Serial

MAC

macOS:

Hardware UUID

System Serial

Linux:

/etc/machine-id

CPU

Disk UUID

最终:

Hash:

SHA256(
machineInfo
)

十四、Device Fingerprint实现

SDK:

public class DeviceFingerprint
{


public string Generate()
{


string raw =
GetMachineId()
+
GetCpuId();


return SHA256Hash(raw);


}


}

十五、Heartbeat机制

目的:

防止:

复制License文件。

客户端:

每天:

或者启动:

调用:

POST

/api/license/heartbeat

数据:

{

licenseId:

"xxx",

deviceId:

"xxx",

version:

"1.0"

}

服务器更新:

LastHeartbeat

十六、防重放攻击

攻击:

截获:

激活请求。

解决:

加入:

Nonce。

请求:

{

licenseKey:"",

nonce:"A82FD91",

timestamp:123456

}

服务器:

保存:

最近Nonce。

检查:

是否使用过

是否超时

十七、离线授权

场景:

工业软件:

无网络。

流程:

服务器生成:

license.dat

内容:

{

payload:{},

signature:"xxx"

}

客户端:

只验证:

签名。


十八、License API Controller

创建:

Controllers/LicenseController.cs

增加:

[HttpPost("activate")]

public async Task<IActionResult>
Activate(
ActivateRequest request)
{


var result =
await service.ActivateAsync(
request);



return Ok(result);


}

十九、缓存策略

Redis缓存:

适合:

频繁验证。

例如:

license:{hash}

TTL:

5分钟

二十、安全增强

生产环境必须:

Private Key

禁止:

放:

appsettings.json

使用:

  • Hashicorp Vault
  • AWS KMS
  • Azure Key Vault

API限流

例如:

同IP:

5分钟100次

超过:

封禁。


二十一、本阶段完成

模块 状态
License Key生成
SHA256存储
ECDSA签名
Public Key验证
激活流程
设备限制
Heartbeat
离线授权
防重放设计
Redis缓存
密钥保护方案

当前系统进度

目前:

数据库

      +

Backend API

      +

License Engine


=


商业授权服务器核心完成

下一章节

第十(五):Client SDK生产代码实现

下一部分将实现:

客户端真正接入:

包括:

  1. LicenseManager
  2. License缓存
  3. AES本地加密
  4. ECDSA验证
  5. Device Fingerprint
  6. Activation Client
  7. Heartbeat Client
  8. Offline License加载
  9. 自动更新接口
  10. SDK NuGet打包

完成后:

任何.NET软件都可以:

LicenseManager.Initialize();

LicenseManager.Activate(key);

直接接入你的商业授权平台。

目前整个《LicenseServer 商业授权系统开发实战》已经进入第十部分源码实现阶段

按照最初规划,后续还有几个核心章节。

目前进度:

章节 内容 状态
第九(一)~(十) 完整商业架构设计 ✅ 已完成
第十(一) Monorepo工程初始化 ✅ 已完成
第十(二) ASP.NET Core Backend基础实现 ✅ 已完成
第十(三) 数据库 + EF Core + Repository ✅ 已完成
第十(四) License Engine核心实现 ✅ 已完成
第十(五) Client SDK实现 ⬅️ 下一章
第十(六) Admin Console完整实现 待完成
第十(七) 支付系统+自动发货实现 待完成
第十(八) Docker生产部署+CI/CD实现 待完成
第十(九) 安全加固与反破解 待完成
第十(十) 商业发行与最终交付 待完成

还剩多少?

如果按照当前路线:

还剩 6 个大章节:


第十(五):Client SDK生产实现

这是下一章。

主要代码:

.NET SDK

实现:

License.Client.SDK

├── LicenseManager

├── ActivationClient

├── LicenseValidator

├── DeviceFingerprint

├── Crypto

├── Storage

└── HeartbeatClient

完成后:

你的软件可以:

var license =
await LicenseManager.ActivateAsync(
"48D0-61CD..."
);


if(license.Valid)
{
    StartApplication();
}

第十(六):Admin Console完整实现

实现后台管理系统。

技术:

Next.js 16

+

TypeScript

+

Tailwind

+

shadcn/ui

+

React Query

页面:

Dashboard

用户管理

License管理

设备管理

订单管理

支付管理

日志审计

系统设置

第十(七):支付 + 自动交付闭环

实现:

用户:

购买软件



Stripe付款



Webhook通知



创建License



发送邮件



用户下载软件



自动激活

包括:

  • Stripe API
  • PayPal扩展设计
  • 邮件系统
  • 下载中心
  • License自动生成

第十(八):生产部署

实现:

服务器:

Ubuntu/Debian

Docker

Nginx

Cloudflare

PostgreSQL

Redis

Vault

包括:

  • docker-compose生产版
  • HTTPS
  • 自动备份
  • 数据恢复
  • 日志系统
  • 监控

第十(九):安全增强

这是商业软件最重要部分。

包括:

服务端安全

  • API Rate Limit
  • WAF
  • SQL防护
  • 密钥轮换

客户端安全

  • 混淆
  • 防调试
  • 防Patch
  • 完整性检查
  • 代码签名

高级:

  • TPM绑定
  • Hardware Key
  • HSM

第十(十):商业发行最终方案

最后收尾:

包括:

软件发行

Windows:

MSIX
Installer
Code Signing

macOS:

Developer ID
Notarization
DMG

Linux:

AppImage
Deb
RPM

商业运营

包括:

  • 用户体系
  • 授权策略
  • 客服流程
  • 数据统计
  • 版本升级

完成后最终成果

最终会形成:

LicensePlatform


├── License Server


├── ASP.NET Core API


├── PostgreSQL


├── Redis


├── Vault



├── Admin Console


├── Client SDK


├── Payment System


├── Auto Delivery


├── CI/CD


└── Deployment

预计剩余工作量

按照现在详细程度:

部分 预计长度
第十(五)SDK 约1~2次回复
第十(六)Admin 约2~3次回复
第十(七)支付系统 约2次回复
第十(八)部署 约2次回复
第十(九)安全 约2~3次回复
第十(十)发行 约1~2次回复

大约:

还有 10~14 次左右内容更新可以完成整个商业版本文档。


下一步继续:

第十(五):Client SDK生产代码实现

这一章非常关键,因为它决定:

你的软件如何安全地接入授权系统,以及如何抵抗简单破解。

会开始写真正客户端代码。

第十(五):Client SDK生产代码实现 继续

LicenseServer 商业授权系统开发实战文档 v1.0

第十部分:完整源码工程实现阶段

第十(五):Client SDK 生产代码实现

本章节实现:

面向 Windows / macOS / Linux 软件的商业授权客户端 SDK。

目标:

任何你的软件项目,只需要引用:

License.Client.SDK.dll

即可接入授权系统。

最终开发体验:

using License.Client;


var result =
await LicenseManager.ActivateAsync(
    "48D0-61CD-35FE-9C9B"
);


if(result.Success)
{
    StartApplication();
}

一、Client SDK设计目标

商业SDK必须满足:

能力 实现
在线激活
离线License
设备绑定
License验证
签名验证
本地缓存
加密存储
Heartbeat
版本检查
跨平台

支持:

  • Windows
  • macOS
  • Linux

.NET支持:

.NET 8+
.NET 10

二、SDK工程结构

项目:

SDK/

License.Client.SDK/

最终:

License.Client.SDK/


├── LicenseManager.cs


├── ActivationClient.cs


├── HeartbeatClient.cs


├── LicenseValidator.cs


├── DeviceFingerprint.cs


├── LicenseStorage.cs


├── OfflineLicenseReader.cs


├── Models/



├── LicenseInfo.cs

├── ActivationResult.cs

├── LicenseResponse.cs



├── Crypto/



├── EcdsaVerifier.cs

├── AesEncryptor.cs



├── Network/



└── ApiClient.cs



└── Exceptions/

三、SDK核心调用流程

软件启动:

Application

    |

    |

LicenseManager


    |

    +----------+

    |          |

 Online    Offline


    |

Activation API


    |

License Server

四、创建SDK项目

进入:

cd src/SDK

创建:

dotnet new classlib \
-n License.Client.SDK

安装:

HTTP:

dotnet add package System.Net.Http.Json

加密:

.NET内置:

无需安装。


五、License模型

路径:

Models/LicenseInfo.cs

代码:

namespace License.Client.Models;


public class LicenseInfo
{


public string LicenseId
{
get;set;
}=""


public string Product
{
get;set;
}=""


public string Plan
{
get;set;
}=""


public int MaxDevices
{
get;set;
}


public DateTime ExpireAt
{
get;set;
}


public bool Valid
{
get;set;
}


public string Signature
{
get;set;
}=""


}

六、ActivationResult

namespace License.Client.Models;


public class ActivationResult
{


public bool Success
{
get;set;
}


public string Message
{
get;set;
}=""


public LicenseInfo?
License
{
get;set;
}


}

七、Device Fingerprint实现

这是设备绑定核心。

文件:

DeviceFingerprint.cs

设计:

不要使用单一硬件信息。

组合:

Windows:

MachineGuid
CPU
BIOS
Disk

Linux:

/etc/machine-id
CPU

macOS:

Hardware UUID
Serial

代码:

using System.Security.Cryptography;
using System.Text;


namespace License.Client;


public class DeviceFingerprint
{


public static string Generate()
{


var raw =
Environment.MachineName
+
Environment.OSVersion
+
Environment.ProcessorCount;



using var sha =
SHA256.Create();



var hash =
sha.ComputeHash(
Encoding.UTF8.GetBytes(raw));



return Convert
.ToHexString(hash);

}


}

生产版本:

后续增加:

  • WMI
  • IOKit
  • Linux DMI

八、本地License存储

不能:

直接:

license.json

因为用户可以修改。

采用:

AES-256-GCM

+

Machine Key

结构:

~/.license/


license.dat

九、AES加密工具

文件:

Crypto/AesEncryptor.cs

代码:

using System.Security.Cryptography;
using System.Text;


namespace License.Client.Crypto;


public class AesEncryptor
{


public static byte[] Encrypt(
string text,
byte[] key)
{


using var aes =
Aes.Create();



aes.Key=key;


aes.GenerateIV();



using var encryptor =
aes.CreateEncryptor();



var data =
Encoding.UTF8
.GetBytes(text);



var encrypted =
encryptor.TransformFinalBlock(
data,
0,
data.Length);



return aes.IV
.Concat(encrypted)
.ToArray();


}



}

十、本地License Storage

文件:

LicenseStorage.cs

代码:

using License.Client.Crypto;


namespace License.Client;


public class LicenseStorage
{


private readonly string path;


public LicenseStorage()
{


path =
Path.Combine(
Environment.GetFolderPath(
Environment.SpecialFolder.ApplicationData),

"license.dat");

}



public void Save(
string data)
{


File.WriteAllText(
path,
data);


}


public string?
Load()
{


if(!File.Exists(path))

return null;



return File.ReadAllText(path);


}


}

十一、ECDSA验证

客户端:

只有:

Public Key。

文件:

Crypto/EcdsaVerifier.cs

代码:

using System.Security.Cryptography;
using System.Text;


namespace License.Client.Crypto;


public class EcdsaVerifier
{


public bool Verify(
string payload,
string signature,
string publicKey)
{


using var ecdsa =
ECDsa.Create();



ecdsa.ImportFromPem(
publicKey);



return ecdsa.VerifyData(

Encoding.UTF8.GetBytes(payload),

Convert.FromBase64String(signature),

HashAlgorithmName.SHA256

);


}


}

十二、API Client

文件:

Network/ApiClient.cs

代码:

using System.Net.Http.Json;


namespace License.Client.Network;


public class ApiClient
{


private readonly HttpClient client;



public ApiClient(
string endpoint)
{

client =
new HttpClient()
{

BaseAddress =
new Uri(endpoint)

};

}



public async Task<T?>
PostAsync<T>(
string url,
object data)
{


var response =
await client.PostAsJsonAsync(
url,
data);



return await response
.Content
.ReadFromJsonAsync<T>();

}


}

十三、Activation Client

文件:

ActivationClient.cs

代码:

using License.Client.Models;


namespace License.Client;


public class ActivationClient
{


private readonly ApiClient api;



public ActivationClient(
ApiClient api)
{

this.api=api;

}



public async Task<ActivationResult?>
ActivateAsync(
string key)
{


var fingerprint =
DeviceFingerprint.Generate();



return await api
.PostAsync<ActivationResult>(
"/api/license/activate",

new
{

licenseKey=key,

deviceFingerprint=fingerprint

});


}

}

十四、Heartbeat Client

文件:

HeartbeatClient.cs

代码:

namespace License.Client;


public class HeartbeatClient
{


public async Task SendAsync(
LicenseInfo license)
{


// 调用服务器heartbeat API


}


}

十五、LicenseManager核心入口

这是开发者使用接口。

文件:

LicenseManager.cs

代码:

using License.Client.Models;


namespace License.Client;


public static class LicenseManager
{


private static LicenseInfo?
_current;



public static LicenseInfo?
Current
=>_current;



public static async Task<ActivationResult>
ActivateAsync(
string key)
{


var api =
new ApiClient(
"https://api.example.com");



var client =
new ActivationClient(api);



var result =
await client
.ActivateAsync(key);



if(result!=null &&
result.Success)
{

_current=
result.License;

}



return result!;


}



public static bool IsValid()
{


return _current!=null
&&
_current.Valid
&&
_current.ExpireAt>DateTime.UtcNow;


}

}

十六、软件接入方式

你的软件:

例如:

static void Main()
{


if(!LicenseManager.IsValid())
{


var result =
LicenseManager.ActivateAsync(
Console.ReadLine()
)
.Result;



if(!result.Success)

return;


}



StartProgram();


}

十七、NuGet发布准备

修改:

.csproj:

<PropertyGroup>

<PackageId>
Company.License.SDK
</PackageId>


<Version>
1.0.0
</Version>


<Authors>
Company
</Authors>


<GeneratePackageOnBuild>
true
</GeneratePackageOnBuild>


</PropertyGroup>

打包:

dotnet pack -c Release

生成:

Company.License.SDK.1.0.0.nupkg

十八、SDK安全增强建议(商业版)

目前:

基础版。

生产增强:

1. Public Key混淆

不要:

publicKey="xxxx"

改:

  • 分段
  • 加密字符串
  • Runtime组合

2. 防Debug

检测:

Debugger.IsAttached

3. 完整性检查

验证:

自身DLL Hash。


4. License缓存加密

升级:

AES-GCM。


5. 防时间回拨

保存:

服务器时间。


十九、本阶段完成

模块 状态
SDK架构
Activation Client
LicenseManager
设备指纹
本地存储
ECDSA验证
Heartbeat框架
NuGet打包
跨平台设计

当前整体进度

Backend




Database




License Engine




Client SDK


下一章节

第十(六):Admin Console 完整实现

下一章进入后台管理系统开发:

技术:

Next.js 16

+

TypeScript

+

Bun

+

Tailwind CSS

+

shadcn/ui

+

React Query

实现:

  • 登录
  • RBAC权限
  • Dashboard
  • 用户管理
  • License生成
  • License查询
  • 设备管理
  • 订单管理
  • 审计日志

完成后,你将拥有完整的:

后台运营控制中心。

LicenseServer 商业授权系统开发实战文档 v1.0

第十部分:完整源码工程实现阶段

第十(六):Admin Console 完整实现

本章节实现:

商业授权系统管理员后台(Admin Console)

Admin Console 是整个商业系统运营入口。

管理员通过后台完成:

  • 创建产品
  • 管理用户
  • 创建License
  • 查看激活设备
  • 管理订单
  • 查看支付状态
  • 风控审计
  • 系统配置

一、技术架构

采用:

Next.js 16

+

TypeScript

+

Bun

+

Tailwind CSS

+

shadcn/ui

+

React Query

+

Zod

+

React Hook Form

架构:

Browser

   |

Next.js App Router

   |

React Components

   |

API Client

   |

ASP.NET Core Backend

二、项目结构

位置:

src/Admin/license-admin

最终结构:

license-admin/


src/


├── app/



├── login/

│   └── page.tsx



├── dashboard/

│   └── page.tsx



├── users/

│   └── page.tsx



├── licenses/

│   └── page.tsx



├── products/

│   └── page.tsx



├── orders/

│   └── page.tsx



├── settings/

│   └── page.tsx



├── components/



├── Sidebar.tsx

├── Header.tsx

├── DataTable.tsx

├── LicenseDialog.tsx



├── lib/



├── api.ts

├── auth.ts

├── utils.ts



├── hooks/



└── useLicense.ts



├── types/


└── license.ts



└── middleware.ts

三、安装依赖

进入:

cd src/Admin/license-admin

使用 Bun:

bun add axios

bun add @tanstack/react-query

bun add zod

bun add react-hook-form

bun add jose

UI:

初始化:

bunx shadcn@latest init

安装组件:

bunx shadcn@latest add \
button \
card \
table \
input \
dialog \
dropdown-menu \
badge \
form

四、环境变量

创建:

.env.local

内容:

NEXT_PUBLIC_API_URL=https://api.example.com

五、API Client

文件:

src/lib/api.ts

代码:

import axios from "axios";


export const api =
axios.create({

baseURL:
process.env
.NEXT_PUBLIC_API_URL,


withCredentials:true

});


api.interceptors.request.use(
(config)=>{


const token =
localStorage.getItem(
"token"
);


if(token)
{

config.headers.Authorization =
`Bearer ${token}`;

}


return config;

}

);

六、认证系统设计

流程:

Admin Login

      |

      |

POST /api/auth/login


      |

      |

JWT Token


      |

      |

localStorage


      |

      |

API Request

七、登录页面

文件:

app/login/page.tsx

代码:

"use client";


import {useState} from "react";
import {api} from "@/lib/api";


export default function Login()
{


const [email,setEmail]=useState("");

const [password,setPassword]=useState("");



async function login()
{


const res =
await api.post(
"/api/auth/login",
{
email,
password
});


localStorage.setItem(
"token",
res.data.token
);



location.href=
"/dashboard";


}



return (

<div>


<input

value={email}

onChange={
e=>setEmail(e.target.value)
}

/>


<input

type="password"

value={password}

onChange={
e=>setPassword(e.target.value)
}

/>


<button
onClick={login}
>

Login

</button>


</div>

);


}

八、后台布局 Layout

文件:

app/dashboard/layout.tsx

代码:

import Sidebar from
"@/components/Sidebar";


export default function Layout(
{
children
}:
{
children:React.ReactNode
}
)
{


return (

<div className="flex">


<Sidebar/>


<main className="flex-1 p-6">

{children}

</main>


</div>


)

}

九、Sidebar菜单

文件:

components/Sidebar.tsx

代码:

"use client";


import Link from "next/link";


export default function Sidebar()
{


return (

<nav>


<Link href="/dashboard">

Dashboard

</Link>


<Link href="/users">

Users

</Link>


<Link href="/licenses">

Licenses

</Link>


<Link href="/orders">

Orders

</Link>


<Link href="/settings">

Settings

</Link>


</nav>


)

}

十、Dashboard首页

显示:

  • 用户数量
  • License数量
  • 收入
  • 激活设备

文件:

app/dashboard/page.tsx

代码:

export default function Dashboard()
{


return (

<div>


<h1>

Dashboard

</h1>


<div className="grid grid-cols-4">


<Card>

Users

1000

</Card>


<Card>

Licenses

5000

</Card>


<Card>

Revenue

$20000

</Card>


<Card>

Devices

8000

</Card>


</div>


</div>

)

}

十一、License管理页面

功能:

管理员:

  • 查询License
  • 创建License
  • 禁用License
  • 查看设备

结构:

/licenses


GET

/api/admin/licenses



POST

/api/admin/licenses


DELETE

/api/admin/licenses/{id}

十二、License列表组件

"use client";


import {useQuery}
from
"@tanstack/react-query";


import {api}
from
"@/lib/api";



export default function Licenses()
{


const {
data
}=useQuery({

queryKey:[
"licenses"
],


queryFn:
async()=>{

const res=
await api.get(
"/api/admin/licenses"
);


return res.data;

}

});



return (

<table>


<tbody>

{
data?.map(
(item:any)=>(


<tr key={item.id}>


<td>

{item.licenseKey}

</td>


<td>

{item.status}

</td>


</tr>


)

)

}


</tbody>


</table>

)

}

十三、创建License弹窗

管理员输入:

用户

产品

套餐

设备数量

有效期

调用:

POST

/api/admin/licenses/create

组件:

components/LicenseDialog.tsx

十四、用户管理

页面:

/users

功能:

  • 搜索用户
  • 查看购买记录
  • 查看License
  • 禁用账户

API:

GET

/api/admin/users

十五、产品管理

产品:

例如:

Video Editor Pro

Image Tool

AI Assistant

字段:

{
"name":"Video Editor",

"code":"VIDEO_PRO"

}

十六、订单管理

页面:

/orders

显示:

字段
订单号
用户
金额
支付状态
创建时间

十七、RBAC权限控制

后台角色:

SuperAdmin

Admin

Support

Finance

权限:

license.create

license.delete

user.manage

payment.view

system.config

十八、前端权限组件

创建:

components/Permission.tsx

代码:

export function Permission(
{
allow,
children
}
)
{


const permissions =
JSON.parse(
localStorage.getItem(
"permissions"
) || "[]"
);



if(
!permissions.includes(allow)
)

return null;



return children;


}

十九、审计日志页面

管理员操作:

必须记录。

显示:

时间

用户

IP

操作

结果

API:

GET

/api/admin/audit

二十、安全设计

Admin Console必须:

1. 强制HTTPS

禁止:

HTTP。


2. 管理员MFA

推荐:

TOTP:

  • Google Authenticator
  • 1Password OTP

3. JWT短周期

推荐:

Access Token:

15分钟

Refresh Token:

7天

4. 登录保护

限制:

5次失败



锁定15分钟

5. 操作审计

例如:

管理员删除License:

记录:

{
"user":"admin",

"action":
"DELETE_LICENSE",

"ip":
"1.2.3.4"

}

二十一、生产构建

开发:

bun dev

生产:

bun run build

启动:

bun start

二十二、Docker部署

Dockerfile:

FROM node:24-alpine


WORKDIR /app


COPY package.json .


RUN npm install


COPY . .


RUN npm run build


CMD [
"npm",
"start"
]

二十三、本阶段完成

模块 状态
Next.js后台框架
登录认证
JWT接入
Dashboard
License管理
用户管理
订单管理
权限系统
审计日志
Docker支持

当前系统进度

目前:

Backend              ✅

Database             ✅

License Engine       ✅

Client SDK           ✅

Admin Console        ✅

已经接近一个完整商业授权平台。


下一章节

第十(七):支付系统 + 自动发货 + 商业闭环实现

下一章实现:

完整商业流程:

用户访问官网



选择套餐



Stripe付款



Webhook通知



创建订单



生成License



发送邮件



用户下载软件



客户端自动激活

包括:

  • Stripe API
  • Webhook安全验证
  • 自动生成License
  • Email系统
  • 下载中心
  • 订单状态机
  • 退款处理

这一章完成后,你的软件授权系统就具备真正商业销售能力。

LicenseServer 商业授权系统开发实战文档 v1.0

第十部分:完整源码实现阶段

第十(七):支付系统 + 自动发货 + 商业闭环实现

本章节开始把前面的:

用户

产品

订单

License

客户端

真正串起来。

最终目标是实现:

用户购买软件

创建订单

第三方支付

支付平台 Webhook

服务器验证支付结果

订单变为 Paid

生成 License

发送交付邮件

用户下载客户端

输入 License

在线激活

这里有一个非常重要的原则:

绝不能根据浏览器前端返回的“支付成功”来发放 License。

只有服务器验证支付平台的可信 Webhook 后,才能把订单标记为已支付并触发发货。


一、商业支付架构

整体结构:

                     ┌──────────────┐
                     │   Customer   │
                     └──────┬───────┘


                     ┌──────────────┐
                     │  Web Store   │
                     └──────┬───────┘


                     ┌──────────────┐
                     │ Order API    │
                     └──────┬───────┘


                     ┌──────────────┐
                     │Payment Provider│
                     └──────┬───────┘

                         Webhook


                     ┌──────────────┐
                     │ Webhook API  │
                     └──────┬───────┘


                 ┌─────────────────────┐
                 │ Order State Machine │
                 └──────────┬──────────┘


                     ┌──────────────┐
                     │License Engine│
                     └──────┬───────┘

                ┌───────────┴───────────┐
                ▼                       ▼
          Email Delivery          Download Center

二、支付系统设计原则

商业系统中建议把:

Order
Payment
License
Delivery

严格分开。

不要设计成:

Payment = License

而应该:

Order

  ├── Payment

  └── License

        └── Devices

这样以后才能支持:

  • 一次订单购买多个License
  • 退款
  • 补发License
  • 更换License
  • 订阅
  • 升级套餐
  • 企业订单

三、订单状态机

建议不要使用一个简单的:

Paid = true

而使用明确状态。

Pending


PaymentPending

   ├──────────────┐
   ▼              ▼
Paid           Failed


Provisioning


Delivered


Completed

退款:

Paid


RefundPending


Refunded

四、OrderStatus

Domain:

Enums/OrderStatus.cs
namespace License.Domain.Enums;

public enum OrderStatus
{
    Pending = 0,
    PaymentPending = 1,
    Paid = 2,
    Provisioning = 3,
    Delivered = 4,
    Completed = 5,
    Failed = 6,
    RefundPending = 7,
    Refunded = 8,
    Cancelled = 9
}

五、PaymentStatus

namespace License.Domain.Enums;

public enum PaymentStatus
{
    Pending = 0,
    Succeeded = 1,
    Failed = 2,
    Refunded = 3,
    PartiallyRefunded = 4
}

六、DeliveryStatus

新增:

Enums/DeliveryStatus.cs
namespace License.Domain.Enums;

public enum DeliveryStatus
{
    Pending = 0,
    Processing = 1,
    Delivered = 2,
    Failed = 3
}

七、重新设计Order实体

前面简单的Order需要升级。

using License.Domain.Enums;

namespace License.Domain.Entities;

public class Order
{
    public Guid Id { get; set; }

    public string OrderNo { get; set; } = "";

    public Guid UserId { get; set; }

    public User User { get; set; } = null!;

    public decimal Amount { get; set; }

    public string Currency { get; set; } = "USD";

    public OrderStatus Status { get; set; }
        = OrderStatus.Pending;

    public DateTime CreatedAt { get; set; }
        = DateTime.UtcNow;

    public DateTime? PaidAt { get; set; }

    public ICollection<Payment> Payments { get; set; }
        = new List<Payment>();

    public ICollection<License> Licenses { get; set; }
        = new List<License>();
}

八、Payment实体升级

using License.Domain.Enums;

namespace License.Domain.Entities;

public class Payment
{
    public Guid Id { get; set; }

    public Guid OrderId { get; set; }

    public Order Order { get; set; } = null!;

    public string Provider { get; set; } = "";

    public string ProviderPaymentId { get; set; } = "";

    public PaymentStatus Status { get; set; }
        = PaymentStatus.Pending;

    public decimal Amount { get; set; }

    public string Currency { get; set; } = "USD";

    public DateTime CreatedAt { get; set; }
        = DateTime.UtcNow;

    public DateTime? CompletedAt { get; set; }
}

九、Webhook必须单独建立事件表

这是商业系统非常重要的一步。

为什么?

支付平台可能重复发送同一个Webhook。

例如:

Webhook #1
Webhook #1
Webhook #1

如果你的程序每次都:

生成License

最终用户可能得到多个License。

所以必须实现:

Idempotency(幂等处理)

创建:

PaymentWebhookEvent.cs
namespace License.Domain.Entities;

public class PaymentWebhookEvent
{
    public Guid Id { get; set; }

    public string Provider { get; set; } = "";

    public string EventId { get; set; } = "";

    public string EventType { get; set; } = "";

    public DateTime ReceivedAt { get; set; }
        = DateTime.UtcNow;

    public DateTime? ProcessedAt { get; set; }

    public bool Processed { get; set; }
}

数据库建立唯一索引:

Provider + EventId

这样同一个支付事件无论收到多少次,只处理一次。


十、支付Provider抽象

不要把业务代码直接写成:

Stripe.xxx();

否则以后换支付渠道会非常麻烦。

定义:

Application/Interfaces/IPaymentProvider.cs
public interface IPaymentProvider
{
    Task<PaymentCheckoutResult>
        CreateCheckoutAsync(
            PaymentCheckoutRequest request);

    Task<bool>
        VerifyWebhookAsync(
            string payload,
            string signature);
}

十一、Checkout Request

public sealed class PaymentCheckoutRequest
{
    public string OrderNo { get; init; } = "";

    public decimal Amount { get; init; }

    public string Currency { get; init; } = "USD";

    public string CustomerEmail { get; init; } = "";

    public string ProductName { get; init; } = "";
}

十二、Checkout Result

public sealed class PaymentCheckoutResult
{
    public string ProviderPaymentId { get; init; } = "";

    public string CheckoutUrl { get; init; } = "";
}

十三、创建订单流程

客户端/网站:

POST /api/orders

请求:

{
  "planId": "xxxxxxxx",
  "quantity": 1
}

服务器:

验证用户

验证Product

验证Plan

计算服务器价格

创建Order

创建Checkout Session

返回Checkout URL

注意:

价格必须由服务器决定。

不能相信浏览器传过来的:

{
    "price": 0.01
}

否则攻击者可以修改前端请求。


十四、OrderService

public async Task<string> CreateOrderAsync(
    CreateOrderRequest request,
    Guid userId)
{
    var plan =
        await _plans.GetAsync(request.PlanId);

    if (plan is null)
        throw new InvalidOperationException(
            "Plan not found.");

    var order = new Order
    {
        Id = Guid.NewGuid(),

        OrderNo = GenerateOrderNo(),

        UserId = userId,

        Amount = plan.Price,

        Currency = "USD",

        Status =
            OrderStatus.PaymentPending
    };

    await _orders.AddAsync(order);

    await _unitOfWork.SaveAsync();

    var checkout =
        await _paymentProvider
            .CreateCheckoutAsync(
                new PaymentCheckoutRequest
                {
                    OrderNo = order.OrderNo,

                    Amount = order.Amount,

                    Currency = order.Currency,

                    ProductName = plan.Name
                });

    return checkout.CheckoutUrl;
}

十五、订单号生成

不要直接使用数据库ID作为订单号。

例如:

LP-20260811-8F3A91C2

代码:

private static string GenerateOrderNo()
{
    return
        $"LP-{DateTime.UtcNow:yyyyMMdd}-" +
        $"{RandomNumberGenerator
            .GetBytes(4)
            .ToHexString()}";
}

生产环境还应该保证数据库唯一约束。


十六、Webhook API

创建:

Controllers/PaymentWebhookController.cs
[ApiController]
[Route("api/payment/webhook")]
public class PaymentWebhookController
    : ControllerBase
{
    private readonly IPaymentWebhookService _service;

    public PaymentWebhookController(
        IPaymentWebhookService service)
    {
        _service = service;
    }

    [HttpPost]
    public async Task<IActionResult> Receive()
    {
        using var reader =
            new StreamReader(
                Request.Body);

        var payload =
            await reader.ReadToEndAsync();

        var signature =
            Request.Headers["X-Payment-Signature"]
                .ToString();

        await _service.ProcessAsync(
            payload,
            signature);

        return Ok();
    }
}

实际接入具体支付平台时,应使用该平台官方SDK/签名验证机制,而不是自行重新实现签名算法。


十七、Webhook处理流程

服务器收到:

Webhook

读取原始Body

验证签名

取得Event ID

查询WebhookEvent

是否已经处理?
   ├── 是 → 直接返回200

   └── 否

     开启数据库事务

     更新Payment

     更新Order

     创建License

     创建Delivery任务

     保存WebhookEvent

     Commit

十八、非常重要:事务边界

不要:

Webhook

更新订单

调用邮件服务器

调用License服务器

...

全部放在一个数据库事务里面。

因为外部网络操作可能超时。

推荐:

数据库事务

Order = Paid

Payment = Succeeded

License = Provisioning

DeliveryJob = Pending

Commit

然后:

Worker



DeliveryJob



生成License



发送邮件



更新DeliveryStatus

这就是:

Outbox / Background Job 模式。


十九、Delivery实体

public class Delivery
{
    public Guid Id { get; set; }

    public Guid OrderId { get; set; }

    public Guid? LicenseId { get; set; }

    public DeliveryStatus Status { get; set; }
        = DeliveryStatus.Pending;

    public int Attempts { get; set; }

    public DateTime CreatedAt { get; set; }
        = DateTime.UtcNow;

    public DateTime? DeliveredAt { get; set; }

    public string? Error { get; set; }
}

二十、自动发货Worker

你的项目已经有:

License.Worker

这里正式使用。

工作流程:

Delivery

Pending

Worker获取任务

创建License

写入数据库

发送交付邮件

Delivered

二十一、为什么不能直接在Webhook生成License?

例如:

Webhook()
{
    CreateLicense();
    SendEmail();
}

不推荐。

因为:

  • Webhook可能重复
  • 邮件可能失败
  • License生成可能失败
  • Webhook请求可能超时
  • 支付平台可能重试

更好的:

Webhook

数据库记录

Worker

二十二、License自动发放

Worker:

public async Task ProcessDeliveryAsync(
    Delivery delivery)
{
    delivery.Status =
        DeliveryStatus.Processing;

    await _unitOfWork.SaveAsync();

    try
    {
        var license =
            await _licenseIssuer
                .IssueAsync(
                    delivery.OrderId);

        delivery.LicenseId =
            license.Id;

        await _emailService
            .SendLicenseAsync(
                license);

        delivery.Status =
            DeliveryStatus.Delivered;

        delivery.DeliveredAt =
            DateTime.UtcNow;
    }
    catch (Exception ex)
    {
        delivery.Attempts++;

        delivery.Status =
            DeliveryStatus.Failed;

        delivery.Error =
            ex.Message;
    }

    await _unitOfWork.SaveAsync();
}

二十三、失败重试

例如:

第一次失败

1分钟后

第二次失败

5分钟后

第三次失败

30分钟后

第四次失败

进入Dead Letter

不要无限重试。

推荐:

MaxAttempts = 5

二十四、Email系统

建议抽象:

public interface IEmailService
{
    Task SendLicenseAsync(
        License license);

    Task SendOrderConfirmationAsync(
        Order order);

    Task SendRefundNotificationAsync(
        Order order);
}

这样以后可以替换邮件服务商。


二十五、License交付邮件

邮件中建议包含:

订单号

产品名称

套餐

License Key

有效期

最大设备数

下载地址

账户管理地址

但是:

不要把数据库中的License私密数据直接全部输出到邮件。

只发送用户真正需要的信息。


二十六、License Key找回功能

你最初的需求中有:

用户填写邮箱,之后可以找回激活码。

商业系统建议:

不要提供:

输入邮箱

直接显示全部License Key

因为邮箱一旦泄露,就可能成为授权泄露入口。

推荐:

用户输入邮箱

发送一次性验证邮件

用户验证

进入License中心

显示License状态

如果确实需要找回完整Key:

邮箱验证
+
一次性Token
+
短时间有效

二十七、License页面

用户登录:

/account/licenses

显示:

Video Editor Pro

License:
48D0-61CD-35FE-....

Status:
Active

Devices:
2 / 3

Expires:
2027-08-11

二十八、下载中心

推荐:

/downloads

例如:

Video Editor Pro

Windows
Version 1.0.0

macOS
Version 1.0.0

Linux
Version 1.0.0

每个文件:

服务器保存:

Version
Platform
Architecture
SHA256
Signature
ReleaseDate

客户端下载后:

下载

SHA256验证

数字签名验证

安装

二十九、退款流程

退款不能简单:

Payment = Refunded

应该:

Refund Request

Payment Provider

Webhook

Order = Refunded

License = Revoked

但是这里要注意:

是否立即撤销License应该由你的商业退款政策决定。

例如:

付款后立即退款
→ 撤销License

部分退款
→ 按政策处理

人工退款
→ Admin确认后处理

三十、License撤销

增加:

public enum LicenseStatus
{
    Active,
    Expired,
    Suspended,
    Revoked
}

退款后:

LicenseStatus = Revoked

客户端下一次:

Heartbeat

服务器返回:

{
  "valid": false,
  "reason": "LicenseRevoked"
}

三十一、Webhook安全

必须满足:

1. HTTPS

https://api.example.com

2. 验证Webhook签名

3. 验证Event ID

4. 幂等处理

5. 数据库事务

6. 不信任前端支付结果

7. 不把Webhook秘密写入Git


三十二、支付密钥配置

禁止:

var secret =
"sk_live_xxxxx";

禁止:

appsettings.json

提交:

GitHub

应该:

Environment Variables

Secret Manager

Vault / Cloud Secret Manager

三十三、测试环境

开发阶段必须使用:

Test/Sandbox Environment

不要直接拿真实支付环境测试。

测试:

成功支付

失败支付

取消支付

Webhook重复

Webhook乱序

退款

部分退款

网络超时

三十四、关键测试

尤其测试:

Webhook重复

发送:

event_001
event_001
event_001

最终:

Order = Paid

License = 1

Delivery = 1

不能:

License = 3

三十五、支付闭环最终状态

完成后:

                  Customer


                 Store Web


                  Order


                Checkout


                  Payment

                  Webhook


              Webhook Handler


               Order = Paid


              Delivery Queue


                License Engine

              ┌──────┴──────┐
              ▼             ▼
          License         Email


        Client Activation

三十六、本阶段完成

模块 状态
订单状态机
Payment模型
Webhook事件模型
幂等处理
支付Provider抽象
Checkout流程
自动License发放
Delivery Worker
邮件交付
退款流程
License撤销
下载中心设计
支付安全

当前完整系统

现在已经形成:

                    LicensePlatform


       ┌───────────────────┼───────────────────┐
       │                   │                   │
       ▼                   ▼                   ▼
    Backend              Admin              Payment
       │                   │                   │
       ▼                   ▼                   ▼
 PostgreSQL             Next.js            Webhook
       │                                       │
       ▼                                       ▼
    Redis                                  License
       │                                       │
       └───────────────────┬───────────────────┘

                       Client SDK

                  ┌────────┼────────┐
                  ▼        ▼        ▼
               Windows   macOS    Linux

下一章是:

第十(八):生产部署 + Docker + CI/CD + 数据库备份恢复

这一章会把目前的代码真正部署到生产服务器,并重点处理:

  • Docker Compose
  • Nginx
  • HTTPS
  • PostgreSQL生产配置
  • Redis
  • Worker
  • Admin
  • API
  • 自动迁移
  • 数据库备份
  • 灾难恢复
  • GitHub Actions
  • Rolling/Blue-Green发布策略
  • 日志与监控
  • Secrets管理

完成第十(八)之后,整个系统就从“开发环境”正式进入可上线的生产环境阶段

LicenseServer 商业授权系统开发实战 v1.0

第十部分:完整源码实现阶段

第十(八):生产部署 + Docker + CI/CD + 数据库备份恢复

这一章开始进入真正的生产环境部署阶段

前面已经完成:

第十(一)  工程初始化
第十(二)  ASP.NET Core Backend
第十(三)  PostgreSQL + EF Core
第十(四)  License Engine
第十(五)  Client SDK
第十(六)  Admin Console
第十(七)  Payment + 自动发货

现在需要把它们部署成一个真正可以长期运行的商业系统。

最终生产架构:

                         Internet


                    ┌──────────────┐
                    │ Cloudflare   │
                    └──────┬───────┘
                           │ HTTPS

                    ┌──────────────┐
                    │    Nginx     │
                    └──────┬───────┘

             ┌─────────────┼─────────────┐
             │             │             │
             ▼             ▼             ▼
        Admin Web       Backend API    Download
        Next.js         ASP.NET Core    Service

                    ┌──────┴──────┐
                    │             │
                    ▼             ▼
               PostgreSQL       Redis


               Backup Storage



                    License Worker
                    Payment Worker

一、生产环境建议

对于你这个项目,我建议第一版商业上线采用:

OS:
Debian 13 / Ubuntu LTS

Container:
Docker Engine

Reverse Proxy:
Nginx

Database:
PostgreSQL

Cache:
Redis

Backend:
ASP.NET Core

Admin:
Next.js

Worker:
.NET Worker Service

CI/CD:
GitHub Actions

TLS:
Cloudflare + Let's Encrypt

Backup:
PostgreSQL + off-site storage

你的开发环境可以继续:

macOS
Windows
Linux

但生产环境建议尽量统一成:

Linux + Docker

这样可以显著降低环境差异。


二、生产目录结构

服务器:

/opt/license-platform/

建议:

/opt/license-platform/

├── compose/

│   ├── compose.prod.yml
│   ├── .env
│   └── nginx/

├── backups/

├── scripts/

│   ├── backup-db.sh
│   ├── restore-db.sh
│   └── deploy.sh

└── data/

注意:

.env

不要提交到 Git。


三、Docker服务划分

最终:

license-api

license-worker

license-admin

postgres

redis

nginx

如果下载服务器单独部署:

download-server

四、生产Docker Compose

文件:

deploy/docker/compose.prod.yml

示例:

services:

  api:
    image: ghcr.io/your-company/license-api:${VERSION}
    restart: unless-stopped

    environment:
      ASPNETCORE_ENVIRONMENT: Production
      ConnectionStrings__Default: ${DATABASE_CONNECTION}
      Redis__ConnectionString: ${REDIS_CONNECTION}

    depends_on:
      postgres:
        condition: service_healthy

      redis:
        condition: service_healthy

    networks:
      - backend


  worker:
    image: ghcr.io/your-company/license-worker:${VERSION}

    restart: unless-stopped

    environment:
      ASPNETCORE_ENVIRONMENT: Production
      ConnectionStrings__Default: ${DATABASE_CONNECTION}
      Redis__ConnectionString: ${REDIS_CONNECTION}

    depends_on:
      postgres:
        condition: service_healthy

    networks:
      - backend


  admin:
    image: ghcr.io/your-company/license-admin:${VERSION}

    restart: unless-stopped

    environment:
      NODE_ENV: production

    networks:
      - frontend


  postgres:
    image: postgres:17

    restart: unless-stopped

    environment:
      POSTGRES_DB: ${POSTGRES_DB}
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}

    volumes:
      - postgres_data:/var/lib/postgresql/data

    healthcheck:
      test:
        [
          "CMD-SHELL",
          "pg_isready -U ${POSTGRES_USER}"
        ]

      interval: 10s
      timeout: 5s
      retries: 5

    networks:
      - backend


  redis:
    image: redis:7-alpine

    restart: unless-stopped

    command:
      [
        "redis-server",
        "--appendonly",
        "yes"
      ]

    volumes:
      - redis_data:/data

    healthcheck:
      test:
        [
          "CMD",
          "redis-cli",
          "ping"
        ]

    networks:
      - backend


  nginx:
    image: nginx:alpine

    restart: unless-stopped

    ports:
      - "80:80"
      - "443:443"

    volumes:
      - ./nginx:/etc/nginx/conf.d:ro
      - ./certs:/etc/nginx/certs:ro

    depends_on:
      - api
      - admin

    networks:
      - frontend
      - backend


volumes:

  postgres_data:

  redis_data:


networks:

  frontend:

  backend:

五、为什么PostgreSQL不能暴露到公网

错误:

Internet


5432

PostgreSQL

绝对不要这样做。

正确:

Internet


Nginx


API


PostgreSQL

PostgreSQL只监听Docker内部网络。


六、生产环境变量

服务器:

/opt/license-platform/compose/.env

例如:

VERSION=1.0.0

POSTGRES_DB=license_platform

POSTGRES_USER=license_app

POSTGRES_PASSWORD=CHANGE_THIS

DATABASE_CONNECTION=Host=postgres;Port=5432;Database=license_platform;Username=license_app;Password=CHANGE_THIS

REDIS_CONNECTION=redis:6379

ASPNETCORE_ENVIRONMENT=Production

但是商业生产环境更推荐:

Vault
AWS Secrets Manager
Azure Key Vault
GCP Secret Manager

而不是长期把数据库密码放在普通 .env 文件里。


七、数据库用户权限

不要让API使用:

postgres

超级管理员账户。

创建:

license_app

只授予业务数据库需要的权限。

例如:

CREATE USER license_app
WITH PASSWORD 'strong-password';

CREATE DATABASE license_platform;

GRANT CONNECT
ON DATABASE license_platform
TO license_app;

生产环境还应进一步限制 schema/table 权限。


八、ASP.NET Core Dockerfile

文件:

src/Backend/License.Api/Dockerfile

推荐多阶段构建:

FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build

WORKDIR /src

COPY . .

RUN dotnet restore

RUN dotnet publish \
    License.Api/License.Api.csproj \
    -c Release \
    -o /app/publish \
    --no-restore


FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS runtime

WORKDIR /app

COPY --from=build \
    /app/publish .

ENV ASPNETCORE_URLS=http://+:8080

EXPOSE 8080

USER $APP_UID

ENTRYPOINT ["dotnet", "License.Api.dll"]

如果你的项目最终统一采用.NET 8 LTS,也可以把:

10.0

统一换成:

8.0

关键是:

整个项目统一Target Framework,不要API用一个大版本、Worker又用另一个版本。


九、Worker Dockerfile

FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build

WORKDIR /src

COPY . .

RUN dotnet restore

RUN dotnet publish \
    License.Worker/License.Worker.csproj \
    -c Release \
    -o /app/publish \
    --no-restore


FROM mcr.microsoft.com/dotnet/runtime:10.0

WORKDIR /app

COPY --from=build \
    /app/publish .

USER $APP_UID

ENTRYPOINT [
    "dotnet",
    "License.Worker.dll"
]

十、Admin Dockerfile

你之前确定:

Next.js
TypeScript
Bun

这里建议真正使用 Bun,而不是之前示例中的 Node。

FROM oven/bun:1 AS deps

WORKDIR /app

COPY package.json bun.lock ./

RUN bun install --frozen-lockfile


FROM oven/bun:1 AS build

WORKDIR /app

COPY --from=deps /app/node_modules ./node_modules

COPY . .

RUN bun run build


FROM oven/bun:1-alpine AS runtime

WORKDIR /app

ENV NODE_ENV=production

COPY --from=build /app/public ./public

COPY --from=build /app/.next ./.next

COPY --from=build /app/node_modules ./node_modules

COPY --from=build /app/package.json ./package.json

EXPOSE 3000

CMD ["bun", "run", "start"]

这样:

macOS
Windows
Linux
CI
Docker

都使用同一个:

bun.lock

减少依赖差异。


十一、Next.js环境变量

需要特别注意:

NEXT_PUBLIC_*

意味着:

这个变量最终可能进入浏览器。

因此:

NEXT_PUBLIC_API_URL=https://api.example.com

可以。

但是:

NEXT_PUBLIC_STRIPE_SECRET_KEY=...

绝对不可以。

Secret只能:

服务器端

使用。


十二、Nginx配置

例如:

api.example.com

配置:

server {

    listen 443 ssl http2;

    server_name api.example.com;

    ssl_certificate
        /etc/nginx/certs/fullchain.pem;

    ssl_certificate_key
        /etc/nginx/certs/privkey.pem;


    location / {

        proxy_pass
            http://api:8080;

        proxy_http_version 1.1;

        proxy_set_header
            Host $host;

        proxy_set_header
            X-Real-IP $remote_addr;

        proxy_set_header
            X-Forwarded-For $proxy_add_x_forwarded_for;

        proxy_set_header
            X-Forwarded-Proto $scheme;
    }
}

十三、Admin域名

例如:

admin.example.com

Nginx:

server {

    listen 443 ssl http2;

    server_name admin.example.com;


    location / {

        proxy_pass
            http://admin:3000;

        proxy_set_header
            Host $host;

        proxy_set_header
            X-Forwarded-For
            $proxy_add_x_forwarded_for;

    }
}

十四、不要让Admin直接访问数据库

错误架构:

Next.js


PostgreSQL

正确:

Next.js


ASP.NET Core API


PostgreSQL

Admin是:

Frontend

而不是数据库管理程序。


十五、EF Core Migration

开发机器:

dotnet ef migrations add InitialCreate

生产:

不要每次:

dotnet ef database update

手动执行。

建议部署流程:

CI

Build

Migration Bundle

审核

Production

Migration

Deploy

十六、Migration Bundle

安装:

dotnet tool install \
--global dotnet-ef

生成:

dotnet ef migrations bundle \
--configuration Release \
-o ./efbundle

生产服务器执行:

./efbundle \
--connection "$DATABASE_CONNECTION"

十七、为什么不推荐API启动时自动Migration

很多项目写:

db.Database.Migrate();

生产环境并不推荐这样做。

因为:

API启动

Migration

Migration锁

多个API实例

可能造成部署问题。

更好的:

CI/CD

Migration Job

完成

部署API

十八、数据库备份

License系统:

数据库就是核心资产。

至少备份:

Users

Orders

Payments

Licenses

Activations

AuditLogs

十九、pg_dump

最简单:

pg_dump \
-h localhost \
-p 5432 \
-U license_app \
-F c \
license_platform \
> license_platform.dump

恢复:

pg_restore \
-h localhost \
-p 5432 \
-U license_app \
-d license_platform \
license_platform.dump

二十、自动备份脚本

文件:

scripts/backup-db.sh
#!/usr/bin/env bash

set -euo pipefail

BACKUP_DIR="/opt/license-platform/backups"

DATE=$(date +"%Y-%m-%d_%H-%M-%S")

mkdir -p "$BACKUP_DIR"

docker exec \
    license-platform-postgres-1 \
    pg_dump \
    -U "$POSTGRES_USER" \
    -d "$POSTGRES_DB" \
    -F c \
    > "$BACKUP_DIR/license_$DATE.dump"


find "$BACKUP_DIR" \
    -type f \
    -mtime +14 \
    -delete

二十一、备份不是只存服务器

这是非常重要的一点。

错误:

服务器

└── backups/

如果:

硬盘损坏
服务器被删除
勒索软件

备份也可能一起丢失。

至少:

生产服务器

       ├── 本地备份

       └── 异地备份

例如:

S3
Cloudflare R2
Backblaze B2
另一台服务器

二十二、3-2-1备份原则

推荐:

3 copies
2 different storage media
1 off-site

例如:

Primary PostgreSQL


      ├── Local backup

      ├── NAS backup

      └── Cloud Object Storage

二十三、备份加密

数据库备份包含:

用户信息
订单
License
邮箱

因此:

Backup本身也必须受到保护。

例如:

gpg \
--symmetric \
license_2026.dump

生产环境更推荐对象存储的服务端加密,并配合严格IAM权限。


二十四、恢复测试

最容易犯的错误:

有备份 ≠ 能恢复。

至少每月进行:

下载备份

创建临时PostgreSQL

Restore

检查License

检查Order

检查User

测试:

SELECT COUNT(*) FROM licenses;

SELECT COUNT(*) FROM orders;

SELECT COUNT(*) FROM users;

二十五、灾难恢复目标

建议定义:

RPO

允许最多丢失:

15分钟

如果商业规模较小:

1小时

也可以接受。


RTO

系统恢复目标:

1小时以内

对于刚开始运营的商业软件已经比较合理。


二十六、Redis备份策略

Redis主要用于:

Cache

Rate Limit

Session

Temporary Data

因此:

Redis不应该成为唯一数据源。

即使Redis全部丢失:

PostgreSQL

仍然应该能够恢复整个授权系统。


二十七、Redis故障

正确设计:

Redis挂掉

API仍然可以运行

部分缓存失效

重新从PostgreSQL加载

而不是:

Redis挂掉

License全部无法验证

二十八、Health Check

API:

GET /health

返回:

{
  "status": "Healthy"
}

更完善:

/health/live

/health/ready

区别:

live

表示:

程序还活着。

ready

表示:

程序已经准备好接收流量。


二十九、Docker Healthcheck

API可以:

healthcheck:

  test:
    [
      "CMD",
      "wget",
      "-q",
      "-O",
      "-",
      "http://localhost:8080/health"
    ]

  interval: 30s

  timeout: 5s

  retries: 3

三十、CI/CD架构

使用:

GitHub



GitHub Actions



Test



Build



Docker Image



GHCR



Production Server



Deploy

三十一、GitHub Actions

文件:

.github/workflows/ci.yml
name: CI

on:

  push:

    branches:
      - main

  pull_request:


jobs:

  backend:

    runs-on: ubuntu-latest

    steps:

      - uses:
          actions/checkout@v4

      - uses:
          actions/setup-dotnet@v4

        with:
          dotnet-version: '10.0.x'

      - run:
          dotnet restore

      - run:
          dotnet build
          --configuration Release
          --no-restore

      - run:
          dotnet test
          --configuration Release

三十二、Admin CI

  admin:

    runs-on: ubuntu-latest

    steps:

      - uses:
          actions/checkout@v4

      - uses:
          oven-sh/setup-bun@v2

        with:
          bun-version: latest

      - run:
          bun install --frozen-lockfile

      - run:
          bun run lint

      - run:
          bun run build

生产环境不建议简单使用:

bun-version: latest

更建议固定到经过测试的版本:

bun-version: 1.x.x

这样可以避免今天构建成功、下个月因为 Bun 新版本导致构建变化。


三十三、Docker Build

例如:

- name:
    Build API image

  run:
    docker build
    -t ghcr.io/company/license-api:${{ github.sha }}
    ./src/Backend

三十四、Push GHCR

- name:
    Login GHCR

  uses:
    docker/login-action@v3

  with:

    registry: ghcr.io

    username:
      ${{ github.actor }}

    password:
      ${{ secrets.GITHUB_TOKEN }}

然后:

- name:
    Push image

  run:
    docker push
      ghcr.io/company/license-api:${{ github.sha }}

三十五、为什么不要只使用latest

不推荐:

license-api:latest

生产环境。

推荐:

license-api:
a82f91c

也可以:

license-api:
1.4.2

最好同时拥有:

semantic version
+
immutable commit SHA

例如:

license-api:1.4.2

license-api:a82f91c

三十六、生产部署

服务器:

cd /opt/license-platform/compose

拉取:

docker compose \
-f compose.prod.yml \
pull

执行Migration:

./scripts/migrate.sh

然后:

docker compose \
-f compose.prod.yml \
up -d

检查:

docker compose ps

三十七、部署顺序

生产部署推荐:

1. Backup Database



2. Pull Images



3. Run Migration



4. Deploy API



5. Deploy Worker



6. Deploy Admin



7. Nginx Reload



8. Health Check



9. Smoke Test

三十八、Smoke Test

上线后自动测试:

curl https://api.example.com/health

然后:

curl https://api.example.com/health/ready

再测试:

登录
创建订单
Sandbox支付
Webhook
License生成
License激活
Heartbeat

三十九、回滚策略

假设:

1.5.0

出现问题。

不要:

重新编译

直接回滚:

1.4.9

例如:

export VERSION=1.4.9

docker compose \
-f compose.prod.yml \
up -d

四十、数据库Migration回滚

这里需要特别小心。

应用可以:

1.5.0

1.4.9

但是数据库:

Migration 20

Migration 19

不一定可以安全回滚。

因此生产数据库Migration应该遵循:

Expand → Migrate → Contract

例如新增字段:

第一版本:
新增字段

第二版本:

开始写入

第三版本:

停止旧字段

第四版本:

删除旧字段

不要在一次部署中:

添加字段
+
删除旧字段
+
修改所有数据

这样回滚风险很高。


四十一、日志

API至少记录:

Request ID

User ID

License ID

Order ID

IP

HTTP Status

Latency

Exception

但是:

不要把License完整Key、密码、支付Secret写进日志。

例如:

错误:

LicenseKey=48D0-61CD-...

推荐:

LicenseId=8d8c...

或者:

LicenseHashPrefix=48D0...

四十二、结构化日志

ASP.NET Core建议:

Serilog

或者直接使用:

Microsoft.Extensions.Logging

输出:

{
  "timestamp":
  "2026-08-11T10:00:00Z",

  "level":
  "Information",

  "event":
  "LicenseActivation",

  "licenseId":
  "xxxx",

  "deviceId":
  "xxxx"
}

四十三、监控

第一阶段:

CPU

RAM

Disk

Container Status

HTTP Status

PostgreSQL

Redis

之后可以增加:

Prometheus
Grafana

监控:

API latency

5xx rate

License activation rate

Payment webhook failures

Worker failures

Database connections

四十四、磁盘监控

这个尤其重要。

如果:

/var/lib/docker

爆满:

可能导致:

PostgreSQL
Docker
Nginx

全部出现异常。

至少监控:

df -h

以及:

docker system df

不要在生产服务器上无脑执行:

docker system prune -a

因为可能删除你后续回滚需要的镜像。


四十五、最终生产架构

最终建议:

                        Cloudflare


                         HTTPS


                          Nginx

             ┌──────────────┴──────────────┐
             │                             │
             ▼                             ▼
       Admin Console                  ASP.NET API
             │                             │
             │                    ┌────────┼────────┐
             │                    │        │        │
             │                    ▼        ▼        ▼
             │                PostgreSQL Redis   Worker
             │                    │                 │
             │                    │                 │
             │                    └───────┬─────────┘
             │                            │
             │                            ▼
             │                     License Engine


       Download Center



                  Payment Webhook

四十六、本阶段最终Checklist

Docker

☑ Multi-stage build
☑ Non-root container
☑ Healthcheck
☑ Restart policy
☑ Internal network
☑ Persistent volumes

PostgreSQL

☑ 不暴露5432
☑ 独立业务用户
☑ 自动备份
☑ 异地备份
☑ Restore测试

Redis

☑ 只允许内部访问
☑ AOF
☑ 不作为核心数据源

API

☑ HTTPS
☑ Health Check
☑ Rate Limit
☑ Structured Logging
☑ Production Config

CI/CD

☑ Automated Test
☑ Docker Build
☑ GHCR
☑ Immutable Image Tag
☑ Migration
☑ Deployment
☑ Rollback

Security

☑ Secrets不进Git
☑ DB不暴露公网
☑ Redis不暴露公网
☑ Admin MFA
☑ Webhook签名验证
☑ Backup加密

四十七、目前系统进度

现在已经完成:

┌────────────────────────────────────┐
│      License Commercial Platform   │
├────────────────────────────────────┤
│                                    │
│  Backend API              ✅       │
│  PostgreSQL               ✅       │
│  EF Core                  ✅       │
│  License Engine           ✅       │
│  Client SDK               ✅       │
│  Admin Console            ✅       │
│  Payment                  ✅       │
│  Auto Delivery            ✅       │
│  Docker                   ✅       │
│  CI/CD                    ✅       │
│  Backup / Restore         ✅       │
│                                    │
└────────────────────────────────────┘

接下来已经进入最后几个非常关键的阶段。

下一章:第十(九)——生产级安全加固与商业软件防破解

这一章会重点处理**“你的授权服务器安全”“你的客户端软件安全”**两个完全不同的层面,包括:

服务器端:

WAF
Rate Limit
Anti-Bot
API Abuse Prevention
RBAC
MFA
Secret Management
Key Rotation
Audit
Webhook Security
Database Security

以及客户端:

License缓存保护
ECDSA验证
设备绑定
时间回拨检测
Replay Protection
代码签名
.NET程序集保护
混淆策略
完整性检测
Native Bridge
TPM / Secure Enclave

其中有一点我会特别调整前面第十(五)的示例:AES-256-GCM、本地密钥保护和设备指纹不能简单地用一个固定的跨平台AES Key实现。真正商业发行时,需要根据 Windows、macOS、Linux 分别利用操作系统的安全存储能力,否则攻击者拿到程序后很容易连加密Key一起拿走。

这一章完成后,再进入第十(十):商业发行、代码签名、Windows/macOS/Linux最终交付与上线Checklist,整个第十部分就基本闭环。

第十(九):生产级安全加固与商业软件防破解

这一章非常关键。前面的系统已经能够:

支付

自动发货

License

客户端激活

设备限制

现在要解决两个不同的问题:

  1. License Server 如何做到商业级安全
  2. 客户端如何提高破解成本

需要先明确一个原则:

客户端永远不是可信环境。

无论你使用 C#、C++、Rust 还是其他语言,只要代码运行在用户自己的电脑上,理论上都可能被分析、修改或调试。

因此真正可靠的商业授权系统不能依赖“客户端绝对无法破解”,而应该采用:

服务器可信
+
客户端多层验证
+
短期授权凭证
+
设备控制
+
异常检测
+
代码签名
+
完整性保护
+
风险控制

形成纵深防御。


一、最终安全架构

推荐最终结构:

                         Internet


                       Cloudflare

                    WAF / Rate Limit


                         Nginx

             ┌──────────────┴──────────────┐
             │                             │
             ▼                             ▼
        Admin Console                  License API

                    ┌──────────────────────┼───────────────────┐
                    │                      │                   │
                    ▼                      ▼                   ▼
               PostgreSQL               Redis             Audit Log


              License Engine


              Risk Detection

客户端:

┌──────────────────────────────────────┐
│             Client App              │
│                                      │
│  License Input                       │
│       ↓                              │
│  Local Validation                    │
│       ↓                              │
│  Device Identity                     │
│       ↓                              │
│  Secure Local Storage                │
│       ↓                              │
│  Server Challenge                   │
│       ↓                              │
│  Signature Verification              │
│       ↓                              │
│  Runtime Integrity                   │
│       ↓                              │
│  Feature Authorization               │
└──────────────────────────────────────┘

二、最重要的密码学架构调整

你最初的需求是:

激活码不能被内部人员随意查看。

这个需求不能简单通过:

AES 加密 LicenseKey

解决。

推荐采用:

License Key


HMAC / SHA-256


License Lookup Hash


Database

数据库不保存明文License Key


三、数据库不要保存完整License Key

不要:

LicenseKey
----------------------
48D0-61CD-35FE-...

改成:

LicenseId
KeyHash
Status
ProductId
MaxDevices
ExpiresAt

例如:

LicenseId:
01JXXXXXXX

KeyHash:
b8c2....

Status:
Active

MaxDevices:
3

四、为什么使用HMAC而不是简单SHA256

如果:

SHA256(LicenseKey)

攻击者拿到数据库以后,可以尝试:

候选License

SHA256

数据库比对

如果License格式比较规律,可能进行离线猜测。

更推荐:

HMAC-SHA256(
    serverSecret,
    licenseKey
)

即:

Hash =
HMACSHA256(
    Secret,
    NormalizedLicenseKey
)

这样数据库泄露后,攻击者无法仅凭数据库进行普通离线验证。


五、License Key格式

你之前设计:

48D0-61CD-35FE-9C9B-5358-3725-D644-1A18

可以继续使用。

总长度:

8 × 4 = 32

十六进制字符。

但是生产环境建议增加熵。

例如:

8组 × 4字符

共:

128 bit

已经足够作为随机License。

关键是:

必须使用密码学安全随机数生成器。

C#:

RandomNumberGenerator

不要:

Random

六、License生成器

using System.Security.Cryptography;

public static class LicenseKeyGenerator
{
    public static string Generate()
    {
        Span<byte> bytes = stackalloc byte[16];

        RandomNumberGenerator.Fill(bytes);

        var hex =
            Convert.ToHexString(bytes);

        return string.Join(
            "-",
            Enumerable.Range(0, 8)
                .Select(i =>
                    hex.Substring(i * 4, 4))
        );
    }
}

生成:

A82F-91C4-7B32-...

七、License Hash

using System.Security.Cryptography;
using System.Text;

public sealed class LicenseHasher
{
    private readonly byte[] _secret;

    public LicenseHasher(string secret)
    {
        _secret =
            Convert.FromBase64String(secret);
    }

    public string Hash(string licenseKey)
    {
        var normalized =
            licenseKey
                .Replace("-", "")
                .Trim()
                .ToUpperInvariant();

        using var hmac =
            new HMACSHA256(_secret);

        var hash =
            hmac.ComputeHash(
                Encoding.UTF8.GetBytes(
                    normalized));

        return Convert.ToHexString(hash);
    }
}

数据库只保存:

KeyHash

八、为什么后台管理员也不应该看到License明文

Admin Console:

错误:

License:
48D0-61CD-35FE-9C9B...

推荐:

License:
••••-••••-••••-9C9B

Status:
Active

Devices:
2 / 3

管理员只能看到:

License ID
Key后4位
用户
产品
状态
设备
创建时间

这样即使Admin账户被盗,风险也小很多。


九、用户找回License怎么办?

这也是为什么之前建议:

License Key

只在首次生成/购买后展示一次。

之后:

用户登录

邮箱验证

License Center

查看授权状态

如果确实需要重新显示完整Key:

重新身份验证
+
Email OTP
+
短期Session

并记录:

LicenseReveal

审计日志。


十、管理员权限进一步细分

建议最终RBAC:

SuperAdmin
Admin
Support
Finance
SecurityAuditor

权限:

license.read
license.create
license.revoke

user.read
user.disable

payment.read
payment.refund

audit.read

security.manage

特别是:

license.reveal

应该成为一个极高权限。

甚至:

默认不存在“查看完整License”的权限。


十一、Admin MFA

管理员不能只使用:

Email
+
Password

必须:

Password
+
MFA

推荐:

TOTP

或者:

WebAuthn / Passkey

商业系统更推荐优先支持Passkey/WebAuthn。


十二、Admin登录安全

登录流程:

Email

Password

Rate Limit

MFA

Session

失败:

5次

短暂锁定

但不要使用永久锁定,否则攻击者可以通过故意失败来阻止管理员登录。


十三、管理员Session

不要使用永久JWT:

JWT = 30 days

推荐:

Access Token
≈ 10~15分钟

Refresh Token
≈ 几天

Refresh Token必须:

Rotation
+
Revocation
+
Device Binding

十四、Refresh Token不要明文保存

数据库不要:

RefreshToken
----------------
eyJhbGciOi...

保存:

TokenHash

服务器收到Token后:

Token

Hash

Database

Compare

十五、API Rate Limit

至少分三层:

IP
+
Account
+
Endpoint

例如:

/api/auth/login

限制:

10 requests / minute / IP

而:

/api/license/activate

可以更严格:

20 requests / minute / IP

具体数值应通过真实流量压测调整,不建议写死为一套“万能数字”。


十六、激活接口必须防爆破

攻击者可能:

AAAA-AAAA-AAAA...
BBBB-BBBB-...
CCCC-CCCC-...

因此:

POST /api/license/activate

必须:

Rate Limit
+
Request Signature
+
Device Challenge
+
Risk Scoring

十七、不要返回过多错误信息

错误:

{
  "error": "License exists but belongs to another user"
}

这会帮助攻击者枚举License。

推荐统一:

{
  "error": "Activation failed"
}

服务器内部日志记录真实原因。


十八、设备ID设计

你需要支持:

1台
3台
5台

因此数据库:

License

   ├── Activation Device A
   ├── Activation Device B
   └── Activation Device C

设备记录:

DeviceId
LicenseId
Platform
AppVersion
FirstSeen
LastSeen
Status

十九、不要把MAC地址当设备ID

不要:

MAC Address

作为唯一设备身份。

原因:

  • 可以修改
  • 虚拟机容易变化
  • 多网卡
  • Docker
  • 隐私问题
  • macOS/Linux/Windows行为不同

推荐:

随机Device Identity
+
OS Secure Storage
+
服务器记录

二十、客户端生成Device Identity

首次启动:

Random 256-bit ID

然后存储到:

Windows:
Credential Manager / DPAPI

macOS:
Keychain

Linux:
Secret Service

如果系统没有可用安全存储:

不要假装它是安全的。

可以降级为普通本地存储,但服务器风险评分提高。


二十一、Windows安全存储

C#:

DPAPI

例如:

ProtectedData.Protect(...)

密钥绑定:

CurrentUser

或者更高安全级别的:

LocalMachine

具体选择取决于你的应用部署模型。


二十二、macOS

推荐:

Keychain Services

不要:

~/.config/app/license.json

里面直接保存:

License
DeviceSecret
RefreshToken

二十三、Linux

优先:

Secret Service

例如:

GNOME Keyring
KWallet

服务器端也必须允许:

Linux Headless

这种场景使用不同策略。


二十四、License Token

客户端激活成功后:

不要每次:

LicenseKey

直接发送。

推荐服务器签发:

License Access Token

例如:

Activation

License Key

Server

验证

Signed License Token

客户端以后使用:

License Token

而不是反复发送原始License Key。


二十五、签名License Token

建议:

Ed25519

或者:

ECDSA P-256

架构:

Server
Private Key


Sign License Token


Client
Public Key


Verify Signature

关键:

私钥永远不能进入客户端。


二十六、为什么非常适合使用非对称签名

客户端里面可以包含:

PUBLIC KEY

即使被提取:

攻击者拿到Public Key

也无法生成:

有效License Token

因为:

Private Key

只存在服务器。

这是整个客户端授权安全的核心之一。


二十七、密钥轮换

不要永久只有:

license-key-v1

推荐:

kid = license-2026-01

Token:

{
  "kid": "license-2026-01",
  "alg": "EdDSA"
}

服务器以后可以:

license-2026-01
license-2027-01

并保留旧公钥验证历史License。


二十八、客户端验证流程

最终:

License Key

Activate

Server

Device Check

License Check

Issue Signed Token

Client

Signature Verify

Secure Storage

启动:

读取Token

验证签名

检查Expiration

检查Device

运行

二十九、在线Heartbeat

不要让客户端:

激活一次

永远离线使用

推荐:

首次激活

在线验证

Token

周期性Heartbeat

例如:

24小时

或者根据产品类型设计更长/更短的验证周期。


三十、离线模式

商业软件通常需要考虑:

飞机
企业内网
没有网络

因此:

Online License
+
Offline Grace Period

例如:

服务器最后验证

允许短期离线运行

超过Grace Period

需要重新验证

具体期限应根据你的商业产品场景决定。


三十一、时间回拨

攻击者可能:

系统时间
2026-08-11



修改成
2025-01-01

客户端不要只相信:

DateTime.Now

可以结合:

LastSuccessfulServerTime

例如:

ServerTime = 2026-08-11
LocalTime  = 2025-01-01

检测:

ClockRollback

然后:

重新在线验证

三十二、Replay Protection

每次客户端请求可以包含:

RequestId
Timestamp
Nonce

例如:

{
  "deviceId": "...",
  "timestamp": 1786440000,
  "nonce": "...",
  "requestId": "..."
}

服务器检查:

Timestamp
Nonce
RequestId

防止攻击者复制以前的合法请求。


三十三、客户端不要把授权逻辑全部集中在一个函数

错误:

if (licenseValid)
{
    StartApplication();
}

攻击者只需要Patch:

licenseValid = true;

因此需要:

License

Feature

Session

Runtime

多处验证。


三十四、但不要做“疯狂反调试”

不要把客户端设计成:

发现Debugger

立即删除文件

或者:

检测虚拟机

破坏用户数据

这种做法不仅不可靠,也容易误伤合法用户。

推荐:

检测

提高风险评分

要求重新在线验证

而不是破坏用户环境。


三十五、.NET程序保护

你的客户端如果使用:

C#
.NET

需要认识到:

.NET程序集天然比Native代码更容易被反编译。

因此商业发行可以使用成熟的:

.NET Obfuscator

对关键程序集进行:

  • 名称混淆
  • 控制流混淆
  • 字符串保护
  • 常量保护
  • Anti-Tamper

但不要试图把整个程序都做成极端混淆。


三十六、关键逻辑Native化

如果授权系统的部分逻辑特别敏感,可以考虑:

C#
Application


Native Library


C++ / Rust

例如:

Device Secret Derivation
Cryptographic Operations
Integrity Checks

但要注意:

Native代码也不是不可破解,只是提高分析成本。


三十七、不要把服务器Secret编译进客户端

这是绝对禁止的:

const string Secret =
    "SUPER_SECRET_123456";

因为:

客户端

反编译

Secret

直接泄露。

客户端最多包含:

Public Key

不能包含:

Private Key
HMAC Master Secret
Database Password
Stripe Secret
Webhook Secret

三十八、客户端完整性

可以对关键程序集计算:

SHA-256

例如:

LicenseClient.dll

启动时:

Hash

Server

Expected Hash

但是这种方案本身也容易被Patch。

所以更推荐:

代码签名
+
完整性检查
+
服务器风险检测

组合使用。


三十九、Windows代码签名

Windows商业发行:

Authenticode

签名:

.exe
.dll
.msi

目标:

Publisher:
Your Company

用户看到:

Verified Publisher

四十、macOS代码签名

macOS商业发行需要:

Apple Developer ID

通常流程:

Build

Code Sign

Hardened Runtime

Notarization

Staple

DMG / PKG

这样用户安装时可信度会高很多。


四十一、Linux

Linux没有完全统一的商业代码签名体验。

建议:

.deb
.rpm
AppImage

同时:

SHA256
+
GPG签名

例如:

app.AppImage
app.AppImage.sha256
app.AppImage.sig

四十二、下载文件安全

下载服务器:

https://download.example.com

不要让API每次:

读取整个安装包

推荐:

Object Storage


Signed URL


Client

例如:

下载链接有效期
10分钟

这样即使链接泄露,也不会永久有效。


四十三、软件更新

客户端:

Current Version

Update API

Latest Version

Download

Signature Verification

Install

不要只检查:

SHA256

因为Hash只能证明:

文件没有被意外修改。

数字签名才能证明:

文件由你的发行密钥签署。


四十四、更新Manifest

例如:

{
  "version": "1.4.2",
  "platform": "windows-x64",
  "url": "...",
  "sha256": "...",
  "signature": "...",
  "minimumClient": "1.2.0"
}

这个Manifest本身也应该进行签名。


四十五、服务器风控

服务器可以建立:

Risk Score

例如:

正常设备
= 0

短时间大量激活
+30

IP异常
+20

设备数量异常
+30

大量失败License
+20

Token Replay
+50

超过阈值:

Risk > 70

要求:

重新验证

而不是直接封号。


四十六、异常激活示例

例如一个License:

最大设备:
3

正常:

China
PC1

China
PC2

China
PC3

可疑:

PC1
PC2
PC3
PC4
PC5
PC6
PC7

服务器:

DeviceLimitExceeded

四十七、不要只根据IP限制设备

不要:

1 IP = 1 Device

因为:

公司
学校
家庭
VPN
NAT

可能大量用户共享IP。

IP应该只是:

Risk Signal

而不是唯一判断依据。


四十八、审计日志

以下事件必须记录:

Login
LoginFailed
LicenseCreated
LicenseActivated
LicenseDeactivated
LicenseRevoked
DeviceAdded
DeviceRemoved
PaymentSucceeded
PaymentRefunded
WebhookFailed
AdminAction
SecurityEvent

例如:

{
  "event": "LicenseActivated",
  "licenseId": "...",
  "deviceId": "...",
  "ip": "...",
  "timestamp": "..."
}

四十九、日志中禁止出现的内容

绝对不要记录:

Password
RefreshToken
Payment Secret
Database Password
Private Key
完整LicenseKey

例如错误:

_logger.LogInformation(
    "License={License}",
    licenseKey);

应该改成:

_logger.LogInformation(
    "License activated: {LicenseId}",
    licenseId);

五十、数据库加密

这里需要区分:

磁盘加密

防止:

硬盘被盗

应用层加密

保护:

数据库泄露

对于特别敏感字段:

CustomerEmail
Payment metadata

可以根据合规需求进行字段级加密。

但是:

License Key最好直接设计为不可逆存储,而不是“加密后还能被管理员解密”。


五十一、Secret Management

生产环境:

Source Code

      ├── ❌ Password
      ├── ❌ Stripe Secret
      ├── ❌ DB Password
      └── ❌ Private Key

应该:

Secret Manager


Application

例如:

AWS Secrets Manager
Azure Key Vault
GCP Secret Manager
HashiCorp Vault

五十二、Private Key保护

License签名私钥是整个系统最重要的资产之一。

不要:

license-private.pem

直接放:

Docker Image

也不要:

Git Repository

生产环境推荐:

KMS / HSM

最终架构:

License Server


KMS / HSM


Sign()

私钥本身不会直接暴露给应用。


五十三、开发环境和生产环境必须分离

必须:

Development
Staging
Production

三套环境。

尤其:

License Signing Key
Payment Secret
Database

不能共用。


五十四、测试License

开发环境:

TEST-XXXX-XXXX

生产:

LIVE-XXXX...

服务器必须区分:

Environment

防止开发人员拿生产License进行测试。


五十五、Staging环境

推荐:

api-staging.example.com

admin-staging.example.com

部署:

GitHub

CI

Staging

自动测试

人工确认

Production

五十六、生产发布审批

商业系统不要:

git push

直接生产

推荐:

Pull Request

CI

Code Review

Security Test

Staging

Approval

Production

五十七、供应链安全

需要固定:

NuGet versions
npm/Bun dependencies
Docker base images
GitHub Actions

不要:

latest

到处乱用。

例如:

postgres:17

长期运行后也应该规划升级策略。

更严格:

postgres:17.x

甚至固定到经过验证的具体版本。


五十八、依赖漏洞扫描

CI加入:

NuGet Audit
npm audit
Trivy
GitHub Dependabot

例如:

Source

Dependency Scan

Docker Scan

SAST

Build

五十九、Docker镜像扫描

生产镜像构建后:

Trivy

检查:

OS vulnerabilities
Library vulnerabilities
Secrets
Misconfigurations

发现严重漏洞:

CI失败

六十、WAF

生产:

Cloudflare

WAF

Nginx

ASP.NET

WAF可以处理:

恶意Bot
扫描
异常请求
DDoS
部分Web攻击

但是:

WAF不是应用安全的替代品。

API自身仍然必须:

Authentication
Authorization
Validation
Rate Limit

六十一、API输入验证

所有输入:

LicenseKey
Email
DeviceId
ProductId
OrderId

都必须验证。

推荐:

FluentValidation

或者:

DataAnnotations

不要相信客户端:

{
  "maxDevices": 999999
}

服务器应该:

Plan

Server-side configuration

MaxDevices

六十二、IDOR防护

例如:

GET /api/licenses/123

攻击者修改:

123 → 124

不能因此看到别人的License。

服务器必须:

CurrentUser
+
ResourceOwner

进行授权检查。


六十三、Admin API和普通API分离

推荐:

/api/v1/license/*

普通用户:

/api/v1/account/*

管理员:

/api/v1/admin/*

并且:

Admin Policy

单独控制。


六十四、API版本控制

不要:

/api/license

永久不变。

建议:

/api/v1/license

以后:

/api/v2/license

这样客户端SDK升级更加安全。


六十五、最终客户端防护层级

建议:

Layer 1
代码签名

Layer 2
程序集保护

Layer 3
License Token签名

Layer 4
Device Identity

Layer 5
Secure Storage

Layer 6
Heartbeat

Layer 7
Replay Protection

Layer 8
Risk Detection

Layer 9
Server-side Authorization

这样即使攻击者绕过其中一层:

仍然无法直接获得完整授权能力。

六十六、不要追求100%防破解

这是商业软件设计中非常重要的认识。

不存在:

100%不可破解

真正的目标应该是:

攻击成本
        >
License购买成本

例如:

购买:
$49

破解需要:
数小时/数天逆向

大多数普通用户就不会选择破解。


六十七、真正应该保护的东西

不是:

if license == true

而是:

License Authority

也就是:

谁拥有授权?
授权什么产品?
允许多少设备?
有效期多久?
当前是否被撤销?

这些最终必须由服务器控制。


六十八、最终安全模型

整个系统最终形成:

                 ┌───────────────────┐
                 │   License Server  │
                 │                   │
                 │  PostgreSQL       │
                 │  License Engine   │
                 │  KMS/HSM          │
                 │  Risk Engine      │
                 └─────────┬─────────┘

                    Signed Token


                 ┌───────────────────┐
                 │     Client        │
                 │                   │
                 │ Public Key        │
                 │ Device Identity   │
                 │ Secure Storage    │
                 │ Integrity Check   │
                 └───────────────────┘

最重要的一条:

Private Key

只在服务器/KMS

客户端:

只有Public Key

六十九、本章节完成Checklist

Server

☑ License Key不可逆存储
☑ HMAC-SHA256
☑ RBAC
☑ Admin MFA
☑ API Rate Limit
☑ Webhook验证
☑ Replay Protection
☑ Audit Log
☑ Secret Management
☑ KMS/HSM规划
☑ WAF
☑ Dependency Scan

Client

☑ Device Identity
☑ Secure Storage
☑ Signed License Token
☑ Token Expiration
☑ Heartbeat
☑ Offline Grace Period
☑ Clock Rollback Detection
☑ Code Signing
☑ Integrity Check
☑ .NET Obfuscation

Infrastructure

☑ HTTPS
☑ DB不暴露公网
☑ Redis不暴露公网
☑ Docker Non-root
☑ Backup Encryption
☑ Off-site Backup
☑ Restore Test
☑ CI/CD
☑ Staging
☑ Production

七十、现在整个第十部分的进度

第十(一)  工程初始化                     ✅

第十(二)  ASP.NET Core Backend            ✅

第十(三)  PostgreSQL + EF Core            ✅

第十(四)  License Server                  ✅

第十(五)  Client SDK                      ✅

第十(六)  Admin Console                   ✅

第十(七)  Payment + 自动发货              ✅

第十(八)  Production + Docker + CI/CD     ✅

第十(九)  Security + Anti-Crack           ✅

第十(十)  商业发行与最终交付              ⏳

因此现在只剩下**第十(十)**这个主要章节。

下一章将把真正面向客户的最终发行体系补齐:

Windows
 ├── EXE
 ├── MSI
 └── Code Signing

macOS
 ├── Universal / x64 / ARM64
 ├── DMG
 ├── Code Signing
 └── Notarization

Linux
 ├── AppImage
 ├── DEB
 └── RPM



Auto Updater

Download Center

License Activation

Crash Reporting

Telemetry

Support

并最终给出一份可以真正用于上线前逐项执行的:

《License Platform 商业上线 Checklist》,把服务器、数据库、支付、License、客户端、域名、HTTPS、代码签名、备份、监控、安全、隐私政策和发布流程全部串起来。

第十(十):商业发行、自动更新与最终上线 Checklist

这一章把前面的系统真正收口到可以商业运营的状态。

最终目标不是单纯“能激活”,而是形成:

                    ┌──────────────┐
                    │   用户购买    │
                    └──────┬───────┘

                    Payment Provider

                    Payment Webhook

                    Order Verification

                    License Generator

                    自动发货 Email

        ┌──────────────────┴─────────────────┐
        ↓                                    ↓
   Download Center                     License Center
        ↓                                    ↓
   安装软件                              管理授权
        ↓                                    ↓
   Client SDK                         Activate Device
        ↓                                    ↓
   License Server ←──────────────→ Device Limit

   Signed License Token

   Software Runtime

一、最终项目结构

建议最终采用 Monorepo:

license-platform/

├── apps/
│   │
│   ├── license-server/
│   │   └── License.Server/
│   │
│   ├── admin-console/
│   │
│   ├── customer-portal/
│   │
│   ├── download-server/
│   │
│   └── docs/

├── sdk/
│   │
│   ├── dotnet/
│   │   ├── License.Client/
│   │   └── License.Client.Abstractions/
│   │
│   ├── native/
│   │
│   └── protocol/

├── clients/
│   │
│   ├── windows/
│   │
│   ├── macos/
│   │
│   └── linux/

├── packages/
│   │
│   ├── shared-contracts/
│   ├── crypto/
│   └── testing/

├── infrastructure/
│   │
│   ├── docker/
│   ├── nginx/
│   ├── postgres/
│   ├── redis/
│   └── monitoring/

├── deploy/
│   │
│   ├── staging/
│   └── production/

├── tests/
│   │
│   ├── unit/
│   ├── integration/
│   ├── security/
│   └── load/

├── scripts/

├── .github/
│   └── workflows/

├── Directory.Build.props
├── Directory.Packages.props
├── global.json
├── docker-compose.yml
└── README.md

二、为什么推荐Monorepo

你的项目本质上存在大量共享模型:

License
Product
Plan
Device
Activation
Order
Customer

如果拆成很多Repository:

license-server
client-sdk
admin
customer-portal
desktop-client

很容易出现:

Server:
LicenseStatus.Active

Client:
LicenseStatus.Enabled

最终协议不一致。

Monorepo可以让:

API Contract
SDK
Server
Tests

一起演进。


三、最终技术栈

结合你之前希望:

macOS + Windows + Linux开发 C# ASP.NET Core PostgreSQL Bun TypeScript

我建议最终版本:

模块 技术
License Server ASP.NET Core
Language C#
ORM EF Core
Database PostgreSQL
Cache Redis
Admin Next.js + TypeScript
Customer Portal Next.js + TypeScript
Package Manager Bun
Client SDK .NET
Windows Client .NET
macOS Client .NET / Native
Linux Client .NET
Container Docker
Reverse Proxy Nginx / Caddy
CI/CD GitHub Actions
Monitoring OpenTelemetry
Logs Loki / Seq / ELK
Metrics Prometheus
Dashboard Grafana

四、TypeScript版本建议

你之前问过:

TypeScript 7.0 能不能使用?

如果你的开发环境已经确认 TypeScript 7.x 与项目依赖兼容,可以使用。

但是商业项目不要因为:

最新版本

就直接升级生产。

推荐原则:

Latest

Compatibility Test

CI

Staging

Production

而不是:

npm/Bun update

生产服务器

尤其:

Next.js
React
TypeScript
ESLint

这些基础设施之间需要验证兼容性。


五、Bun是否可以替代Node.js

可以。

对于:

Admin Console
Customer Portal
Website
Tooling

Bun非常适合。

但是有一个原则:

生产运行时和开发包管理器是两个概念。

你可以:

Bun

install

lockfile

build

Next.js production

但不要让整个License Server依赖Node生态。

因为你的核心后端:

ASP.NET Core

完全独立。

最终:

C#

License Authority

TypeScript/Bun

Web Interface

是很合理的架构。


六、Node.js兼容性

即使你使用Bun,也建议保证:

Node.js compatibility

原因是某些第三方工具:

CLI
CI Action
Build Tool
Security Scanner

仍然假设Node存在。

所以开发电脑可以:

Bun
+
mise

同时保留一个LTS Node作为兼容工具链。


七、数据库最终推荐

生产:

PostgreSQL

开发:

PostgreSQL

测试:

PostgreSQL

不要:

开发:
SQLite

生产:
PostgreSQL

因为容易出现:

SQL差异
Transaction差异
Index差异
Concurrency差异

推荐统一:

Docker PostgreSQL

八、数据库版本策略

不要追求:

最新一天发布的版本

推荐:

PostgreSQL
当前主版本
+
经过验证的稳定小版本

例如:

PostgreSQL 17.x

然后通过:

Minor Upgrade

持续维护。

不要:

postgres:latest

作为生产数据库。


九、Docker最终原则

开发:

postgres:
  image: postgres:17

生产:

固定到经过测试的具体17.x版本

例如:

postgres:17.x

真正上线前记录:

Docker Image Digest

这样可以保证:

今天部署
=
下个月重新部署

尽可能使用同一个镜像。


十、生产Docker结构

推荐:

Internet


Cloudflare


Nginx

    ├── License API
    ├── Admin
    └── Customer Portal


         PostgreSQL

         Redis

数据库:

❌ 不开放公网

Redis:

❌ 不开放公网

只有:

Nginx
License Server
Admin Server
Worker

需要对外开放。


十一、生产域名

推荐:

example.com

拆分:

www.example.com
app.example.com
api.example.com
admin.example.com
download.example.com
status.example.com
docs.example.com

其中:

api.example.com

专门用于License API。


十二、下载中心

建议:

download.example.com

提供:

Windows
macOS
Linux

例如:

Windows x64
Windows ARM64

macOS Apple Silicon
macOS Intel

Linux x64
Linux ARM64

不要让用户自己寻找:

GitHub Release

商业产品应该有自己的Download Center。


十三、版本Manifest

服务器维护:

{
  "product": "MyApp",
  "version": "2.5.0",
  "channel": "stable",
  "platform": "windows-x64",
  "download": "...",
  "sha256": "...",
  "signature": "...",
  "minimumOsVersion": "...",
  "releaseDate": "..."
}

客户端请求:

GET /api/v1/releases/latest

服务器返回:

Latest Version
Download URL
SHA256
Signature

十四、Release Channel

商业软件建议:

stable
beta
nightly

默认:

stable

开发人员:

beta

内部测试:

nightly

这样不会因为:

最新测试版本

导致所有用户一起升级。


十五、自动更新

完整流程:

Application


Check Update


Manifest

    ├── No Update

    └── Update Available


        Download


       Verify Signature


        Verify Hash


           Install


          Restart

十六、自动更新最重要的安全原则

不要:

Download

直接执行

必须:

Download

SHA256

Digital Signature

Trusted Publisher

Install

十七、Windows发行

最终:

MyAppSetup.exe

或者:

MyApp.msi

签名:

Authenticode

最终检查:

☑ EXE签名
☑ DLL签名
☑ Installer签名
☑ Publisher正确

十八、macOS发行

推荐:

MyApp.dmg

支持:

Apple Silicon
Intel

如果客户端是.NET:

Universal

或者分别:

osx-arm64
osx-x64

最终:

Code Sign

Hardened Runtime

Notarization

DMG

十九、Linux发行

建议同时:

AppImage
.deb
.rpm

因为:

Ubuntu/Debian

和:

Fedora/RHEL

用户需求不同。

AppImage作为:

Portable

版本。


二十、客户端首次启动

最终体验建议:

┌─────────────────────────────┐
│          MyApp              │
│                             │
│  Welcome                    │
│                             │
│  License Key                │
│  ┌───────────────────────┐  │
│  │ XXXX-XXXX-XXXX-XXXX   │  │
│  └───────────────────────┘  │
│                             │
│        [ Activate ]         │
│                             │
│  Already activated?         │
│  Sign in                    │
└─────────────────────────────┘

二十一、激活成功

服务器:

License

Customer

Device

Activation

Signed Token

客户端:

Activation successful

显示:

Plan:
Professional

Devices:
2 / 3

Expires:
2027-08-11

不要显示:

服务器内部ID
风险评分
HMAC
Token

二十二、设备管理

Customer Portal:

My Licenses

Professional
3 Devices

────────────────────

Windows PC
Activated:
2026-08-01

macOS
Activated:
2026-08-04

Linux
Activated:
2026-08-08

用户可以:

Deactivate

释放:

1 Device

二十三、防止“无限释放设备”

否则:

激活

释放

另一台

释放

另一台

就失去设备限制意义。

可以加入:

Device Change Policy

例如:

30 days
允许更换N次

或者:

正常用户:
自由管理

异常大量更换:
需要重新验证

不要仅凭IP粗暴封禁。


二十四、退款自动处理

支付:

Payment

Order

License

退款:

Refund

Webhook

Order Refunded

License

Suspended

这样不会出现:

退款成功
+
License仍然永久有效

二十五、订阅产品

如果以后支持订阅:

Monthly
Yearly
Lifetime

License模型不要写死。

推荐:

License

Plan

Entitlement

例如:

Professional
 ├── Feature A
 ├── Feature B
 ├── 3 Devices
 └── Cloud Sync

二十六、Feature Entitlement

这是未来扩展非常重要的一层。

不要:

if (license.Plan == "Pro")

到处写。

应该:

License

Entitlements

Feature

例如:

{
  "cloudSync": true,
  "exportPdf": true,
  "maxDevices": 3
}

这样以后增加:

Enterprise
Team
Ultimate

不需要大量修改客户端代码。


二十七、客服体系

商业软件一定需要:

Support

用户可能遇到:

License无法激活
设备达到上限
换电脑
退款
邮箱变更
订单找不到

Customer Portal应该支持:

Ticket

至少记录:

Order ID
License ID
Customer ID
Issue
Status
CreatedAt

二十八、状态页面

建议:

status.example.com

显示:

License API       Operational
Activation        Operational
Payment           Operational
Download          Operational
Customer Portal   Operational

发生故障时:

Investigating
Identified
Monitoring
Resolved

这对商业产品非常有价值。


二十九、监控

生产至少监控:

CPU
Memory
Disk
Network
Database
Redis
API latency
HTTP 5xx
Activation failure
Payment failure
Webhook failure

重点指标:

License activation success rate

例如:

正常:
99.8%

异常:
85%

应该触发告警。


三十、OpenTelemetry

ASP.NET Core建议统一:

OpenTelemetry

采集:

Traces
Metrics
Logs

例如:

POST /api/v1/license/activate

       ├── API
       ├── License Engine
       ├── PostgreSQL
       └── Redis

可以快速定位:

到底慢在哪。

三十一、备份策略

数据库:

Daily Full Backup
+
WAL / PITR

至少:

3-2-1 Backup

即:

3 copies
2 different storage
1 off-site

三十二、备份加密

不要:

database.sql

裸放:

/home/backups

推荐:

Encrypt

Object Storage

并限制:

Backup Access

三十三、恢复测试

最重要的一点:

有备份 ≠ 能恢复。

至少定期:

Create Test Server

Restore Database

Run Migration

Start API

Test Login

Test Activation

如果恢复不了:

备份实际上没有价值。

三十四、灾难恢复

需要明确:

RPO
RTO

例如:

RPO = 15 min
RTO = 1 hour

意思:

最多丢15分钟数据

1小时内恢复服务

具体目标根据业务规模确定。


三十五、CI/CD最终流程

Developer


Git Push


Pull Request


──────────────
CI
──────────────

    ├── Build
    ├── Unit Test
    ├── Integration Test
    ├── SAST
    ├── Dependency Scan
    ├── Docker Scan
    └── License Test


         Staging


       Approval


       Production

三十六、Release Tag

正式发布:

v1.0.0

而不是:

latest

建议采用:

Semantic Versioning

例如:

1.0.0
1.0.1
1.1.0
2.0.0

三十七、数据库Migration不要自动乱跑

生产:

Application Start

自动Migration

对于重要商业系统不建议无条件这么做。

推荐:

Build

Migration Artifact

Backup

Migration

Deploy Application

这样可以控制数据库变更。


三十八、上线前必须做压力测试

模拟:

100
500
1000
5000

并发激活请求。

重点观察:

CPU
DB connections
Redis
API latency
Lock contention
License uniqueness

尤其测试:

同一个License
100个请求同时激活

最终必须保证:

MaxDevices = 3

不会因为并发导致:

3 → 5

三十九、License并发测试

这是License Server最重要的测试之一。

例如:

License:
MAX_DEVICES = 3

同时发送:

Device A
Device B
Device C
Device D
Device E

数据库最终只能:

A
B
C

而:

D
E

必须失败。

必须使用:

Database Transaction
+
Unique Constraint
+
正确的并发控制

不能仅依赖C#:

if (devices.Count < max)

因为两个请求可能同时读取:

2 devices

然后都认为:

2 < 3

最终变成4台。


四十、最终数据库安全约束

数据库层必须保护业务规则。

例如:

LicenseDevice

建立唯一约束:

LicenseId
+
DeviceId

避免:

同一个设备
重复激活

同时:

License

必须有:

Unique(KeyHash)

保证License不会重复。


四十一、商业上线Checklist

A. 域名

☐ 主域名
☐ API域名
☐ Admin域名
☐ Download域名
☐ Status域名
☐ Docs域名

B. HTTPS

☐ HTTPS
☐ HTTP → HTTPS
☐ TLS配置
☐ HSTS
☐ Certificate Monitoring

C. Server

☐ Production Server
☐ Firewall
☐ SSH安全
☐ Non-root
☐ Docker
☐ Nginx
☐ Cloudflare/WAF

D. Database

☐ PostgreSQL
☐ Private Network
☐ Backup
☐ PITR
☐ Restore Test
☐ Monitoring

E. Redis

☐ Private Network
☐ Authentication
☐ Persistence策略
☐ Memory Limit

F. License

☐ HMAC KeyHash
☐ Device Limit
☐ Device Management
☐ Signed Token
☐ Ed25519/ECDSA
☐ Key Rotation
☐ Revocation
☐ Heartbeat
☐ Offline Grace

G. Security

☐ Admin MFA
☐ RBAC
☐ Rate Limit
☐ WAF
☐ Audit Log
☐ Secret Manager
☐ KMS/HSM
☐ Dependency Scan
☐ Container Scan

H. Client

☐ Windows
☐ macOS Intel
☐ macOS Apple Silicon
☐ Linux
☐ Secure Storage
☐ Code Signing
☐ Auto Update
☐ Signature Verification
☐ Crash Reporting

I. Payment

☐ Payment Provider
☐ Webhook
☐ Webhook Signature
☐ Idempotency
☐ Order
☐ Refund
☐ License Creation
☐ Automatic Delivery

J. Monitoring

☐ Logs
☐ Metrics
☐ Traces
☐ Alerting
☐ Status Page
☐ Error Tracking

四十二、正式上线前的安全测试

至少进行:

Authentication Test
Authorization Test
IDOR Test
Rate Limit Test
Replay Test
Brute Force Test
SQL Injection Test
XSS Test
CSRF Test
SSRF Test
Webhook Replay Test
License Race Test
Device Limit Test
Token Forgery Test
Expired Token Test
Clock Rollback Test

特别是:

Token Forgery

必须测试:

修改payload
修改expiration
修改licenseId
修改deviceId
修改plan

任何修改都必须:

Signature Invalid

四十三、最终安全边界

最终应该做到:

攻击者获得客户端

可以分析客户端

可以看到Public Key

可以看到API Endpoint

可以修改本地程序

但是:

无法伪造服务器签名
无法修改服务器License
无法突破服务器设备限制
无法直接读取数据库License Key
无法伪造支付Webhook
无法获得服务器Private Key

这才是真正的商业License系统。


四十四、你这个项目最终可以形成的产品

最终不仅仅是一个:

License激活程序

而是一套完整的:

Commercial Licensing Platform

包括:

┌─────────────────────────────────────┐
│           Commercial Platform       │
├─────────────────────────────────────┤
│                                     │
│  Customer Portal                    │
│  Admin Console                      │
│  License Server                     │
│  Payment System                     │
│  Automatic Delivery                 │
│  Device Management                  │
│  Client SDK                         │
│  Update Server                      │
│  Download Center                    │
│  Security Engine                    │
│  Analytics                          │
│  Audit System                       │
│  Monitoring                         │
│                                     │
└─────────────────────────────────────┘

以后甚至可以把它做成:

SaaS License Platform

让其他软件开发者购买你的License服务。


四十五、整个第十部分至此完成

现在完整路线已经从:

第十(一)
项目初始化

第十(二)
ASP.NET Core

第十(三)
PostgreSQL + EF Core

第十(四)
License Server

第十(五)
Client SDK

第十(六)
Admin Console

第十(七)
Payment + 自动发货

第十(八)
Docker + CI/CD + Backup

第十(九)
Security + Anti-Crack

第十(十)
Commercial Release

第十部分完整结束。

不过,如果你的目标不是“文档完成”,而是真的把这个项目开发出来,下一阶段就不应该继续无限增加章节,而应该进入真正的工程实现阶段

我建议下一步直接进入:

第十一部分:从零创建真实可运行的完整项目

按照真实开发顺序逐文件实现:

01. Git Repository
02. .NET Solution
03. ASP.NET Core API
04. PostgreSQL
05. EF Core
06. Redis
07. Identity / Admin Auth
08. License Domain
09. License Engine
10. Device Activation
11. Signed Token
12. Client SDK
13. Admin Console
14. Customer Portal
15. Payment
16. Webhook
17. Email Delivery
18. Docker
19. CI/CD
20. Windows/macOS/Linux Client
21. Code Signing
22. Auto Update
23. Integration Tests
24. Security Tests
25. Production Deployment

而且这一阶段我建议不再用伪代码,直接按照你之前确定的 C# + ASP.NET Core + PostgreSQL + EF Core + Redis + Next.js + TypeScript + Bun + Docker 技术栈,给出可以逐文件创建、编译、运行和部署的实际工程代码。

帮我下个简单的项目部署文档,方便我直播部署

可以。下面给你一份适合直播演示/录屏部署的简化版文档。为了直播稳定,我建议不要一开始就部署完整的支付、监控、CI/CD,而是先把 ASP.NET Core + PostgreSQL + Redis + Next.js 跑起来,确认 License API 能正常工作,再逐步扩展。

License System 简易部署文档

1. 部署架构

直播时直接展示这一套:

                    Internet


                  Nginx / Caddy

          ┌────────────┴────────────┐
          │                         │
          ▼                         ▼
   ASP.NET Core API            Next.js Admin

      ┌───┴────┐
      ▼        ▼
 PostgreSQL   Redis

服务器建议:

OS: Debian 13 / Ubuntu 24.04 LTS
CPU: 2 Core+
RAM: 4 GB+
Disk: 40 GB+
Docker: 最新稳定版

如果只是直播演示:

2 Core
4 GB RAM
40 GB SSD

基本够用。


2. 项目目录

服务器统一:

/opt/license-platform

结构:

/opt/license-platform/
├── docker-compose.yml
├── .env
├── postgres/
├── redis/
├── backups/
└── nginx/

以后正式生产再增加:

monitoring/
deploy/
scripts/

3. 安装 Docker

Ubuntu / Debian:

sudo apt update
sudo apt install -y ca-certificates curl git

安装 Docker:

curl -fsSL https://get.docker.com | sudo sh

检查:

docker --version
docker compose version

应该看到:

Docker version ...
Docker Compose version ...

4. 创建项目目录

sudo mkdir -p /opt/license-platform
sudo chown -R $USER:$USER /opt/license-platform

进入:

cd /opt/license-platform

5. 创建 .env

nano .env

直播演示可以使用:

POSTGRES_DB=license_db
POSTGRES_USER=license_user
POSTGRES_PASSWORD=CHANGE_THIS_PASSWORD

REDIS_PASSWORD=CHANGE_THIS_REDIS_PASSWORD

ASPNETCORE_ENVIRONMENT=Production

真实生产环境不要直接使用这组示例密码。

建议生成:

openssl rand -base64 32

例如:

POSTGRES_PASSWORD=这里填写生成的随机密码
REDIS_PASSWORD=这里填写生成的随机密码

6. Docker Compose

创建:

nano docker-compose.yml

先使用这个简化版本:

services:

  postgres:
    image: postgres:17
    container_name: license-postgres
    restart: unless-stopped

    environment:
      POSTGRES_DB: ${POSTGRES_DB}
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}

    volumes:
      - postgres_data:/var/lib/postgresql/data

    networks:
      - license_network

    healthcheck:
      test:
        [
          "CMD-SHELL",
          "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"
        ]
      interval: 10s
      timeout: 5s
      retries: 5


  redis:
    image: redis:7-alpine
    container_name: license-redis
    restart: unless-stopped

    command:
      - redis-server
      - --requirepass
      - ${REDIS_PASSWORD}

    volumes:
      - redis_data:/data

    networks:
      - license_network

    healthcheck:
      test:
        [
          "CMD",
          "redis-cli",
          "-a",
          "${REDIS_PASSWORD}",
          "ping"
        ]
      interval: 10s
      timeout: 5s
      retries: 5


  license-server:
    image: your-registry/license-server:latest
    container_name: license-server
    restart: unless-stopped

    environment:
      ASPNETCORE_ENVIRONMENT: ${ASPNETCORE_ENVIRONMENT}

      ConnectionStrings__DefaultConnection: >-
        Host=postgres;
        Port=5432;
        Database=${POSTGRES_DB};
        Username=${POSTGRES_USER};
        Password=${POSTGRES_PASSWORD}

      ConnectionStrings__Redis: >-
        redis:6379,password=${REDIS_PASSWORD}

    depends_on:
      postgres:
        condition: service_healthy

      redis:
        condition: service_healthy

    ports:
      - "8080:8080"

    networks:
      - license_network


volumes:
  postgres_data:
  redis_data:


networks:
  license_network:
    driver: bridge

7. 启动数据库

第一次直播建议先:

docker compose pull

然后:

docker compose up -d postgres redis

检查:

docker compose ps

应该看到:

license-postgres
license-redis

状态:

healthy

8. 测试 PostgreSQL

进入数据库:

docker exec -it license-postgres \
psql -U license_user -d license_db

执行:

SELECT version();

退出:

\q

9. 测试 Redis

docker exec -it license-redis \
redis-cli -a "你的Redis密码"

执行:

PING

返回:

PONG

退出:

exit

10. 部署 ASP.NET Core

如果你的镜像已经上传到 Registry:

docker compose pull license-server

然后:

docker compose up -d license-server

检查:

docker compose ps

查看日志:

docker compose logs -f license-server

看到类似:

Now listening on: http://[::]:8080
Application started

说明API已经启动。


11. 测试 API

服务器执行:

curl http://127.0.0.1:8080/health

如果你的健康检查接口是:

/health

应该返回:

{
  "status": "Healthy"
}

12. 如果还没有 Docker 镜像

开发机直接构建:

docker build \
  -t license-server:local \
  ./apps/license-server

查看:

docker images

然后运行:

docker run --rm \
  license-server:local

不过直播时我更推荐:

GitHub

GitHub Actions

Docker Image

GHCR

服务器 docker pull

这样演示会更加接近真正的商业部署流程。


13. Nginx反向代理

安装:

sudo apt install -y nginx

创建:

sudo nano /etc/nginx/sites-available/license

简单配置:

server {
    listen 80;
    server_name api.example.com;

    location / {
        proxy_pass http://127.0.0.1:8080;

        proxy_http_version 1.1;

        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

启用:

sudo ln -s \
/etc/nginx/sites-available/license \
/etc/nginx/sites-enabled/license

检查:

sudo nginx -t

然后:

sudo systemctl reload nginx

14. HTTPS

直播环境最简单:

Cloudflare

Nginx

ASP.NET Core

如果使用Let’s Encrypt:

sudo apt install -y certbot python3-certbot-nginx

然后:

sudo certbot --nginx \
-d api.example.com

测试:

curl https://api.example.com/health

15. PostgreSQL绝对不要开放公网

检查:

sudo ss -lntp

不要出现:

0.0.0.0:5432

也不要:

0.0.0.0:6379

正确应该是:

Internet


Nginx :443


API :8080

   ├── PostgreSQL
   └── Redis

PostgreSQL和Redis只存在于Docker内部网络。


16. EF Core Migration

进入API容器:

docker exec -it license-server bash

如果容器内包含EF工具,可以:

dotnet ef database update

更推荐正式生产:

Build

Migration

Backup

Migration

Deploy

而不是每次API启动自动修改生产数据库。


17. 第一次启动完整流程

直播时直接按照下面执行即可:

cd /opt/license-platform

然后:

docker compose pull

启动:

docker compose up -d postgres redis

检查:

docker compose ps

然后:

docker compose up -d license-server

检查:

docker compose ps

查看:

docker compose logs -f license-server

最后:

curl http://127.0.0.1:8080/health

18. 停止系统

docker compose stop

注意:

stop

不会删除数据库。


19. 重启系统

docker compose restart

或者:

docker compose up -d

20. 查看日志

全部:

docker compose logs

实时:

docker compose logs -f

只看API:

docker compose logs -f license-server

只看数据库:

docker compose logs -f postgres

21. 更新版本

以后发布:

v1.0.1

服务器:

docker compose pull

然后:

docker compose up -d

检查:

docker compose ps

最后:

docker compose logs -f license-server

22. 数据库备份

创建:

mkdir -p /opt/license-platform/backups

执行:

docker exec license-postgres \
pg_dump \
-U license_user \
-d license_db \
> /opt/license-platform/backups/license_$(date +%Y%m%d_%H%M%S).sql

查看:

ls -lh backups/

23. 数据库恢复

例如:

backups/license_20260811_120000.sql

执行:

cat backups/license_20260811_120000.sql | \
docker exec -i license-postgres \
psql -U license_user -d license_db

正式生产恢复前应先停止写入,并优先在恢复环境验证备份。


24. 直播部署检查表

直播前先准备:

☐ 云服务器
☐ 域名
☐ DNS
☐ Docker
☐ Git
☐ Docker Registry
☐ PostgreSQL
☐ Redis
☐ License Server镜像
☐ .env
☐ Nginx
☐ HTTPS

直播过程中:

☐ 创建服务器
☐ 安装Docker
☐ Clone项目
☐ 配置.env
☐ 启动PostgreSQL
☐ 启动Redis
☐ 启动License Server
☐ 执行Migration
☐ 测试/health
☐ 配置Nginx
☐ 配置HTTPS
☐ 测试公网API
☐ 创建License
☐ 客户端激活

25. 最适合直播演示的最终效果

直播最后可以展示:

浏览器


https://api.example.com/health


┌──────────────────┐
│ ASP.NET Core API │
└────────┬─────────┘

    ┌────┴────┐
    ▼         ▼
PostgreSQL   Redis

然后:

Admin Console


创建 License


48D0-61CD-35FE-9C9B...


Windows / macOS / Linux


Activate


License Server


Activation Successful

这样一场直播就能把**“服务器部署 → 数据库 → API → License生成 → 客户端激活”**完整跑通。

**建议你直播时先不要把支付、自动更新、KMS/HSM、监控集群等复杂部分放进去。**先完成这一条最核心的商业闭环,后面再逐个加入。

把这个也写出来吧,方便我以后补充

可以。建议把这部分单独保存成项目里的 《第十一部分:生产环境扩展部署手册》,以后你开发到支付、Admin、自动更新、监控等模块时,可以直接往里面补充,不需要重新整理整套部署文档。

下面我直接给你一份可作为项目正式文档的版本

第十一部分:生产环境扩展部署手册

文档版本:v1.0 适用项目:License Management Platform 技术栈:ASP.NET Core + PostgreSQL + Redis + Next.js + TypeScript + Bun + Docker 目标环境:Debian / Ubuntu Linux 开发环境:Windows / macOS / Linux

1. 文档目的

本章节用于记录 License 商业授权系统从基础部署逐步扩展到完整生产环境所需要的部署配置。

基础部署完成后,可以按照以下顺序逐步增加:

基础 API

Admin Console

Customer Portal

Payment

自动发货

Email

HTTPS

Monitoring

Backup

CI/CD

Auto Update

Security Hardening

Production HA

不要求第一次部署全部完成。

2. 推荐生产架构

最终生产环境:

                         Internet


                       Cloudflare

                     WAF / DDoS


                         Nginx

            ┌───────────────┼────────────────┐
            │               │                │
            ▼               ▼                ▼
       License API       Admin Web       Customer Web

       ┌────┴─────────────┐
       │                  │
       ▼                  ▼
 PostgreSQL             Redis


 Backup / Object Storage

后台任务:

Payment Worker
Email Worker
License Worker
Update Worker
Cleanup Worker

监控:

ASP.NET Core


OpenTelemetry

 ┌────┼─────┐
 ▼    ▼     ▼
Logs Metrics Traces
 │     │      │
 ▼     ▼      ▼
Loki Prometheus Tempo


           Grafana

3. 服务器规划

3.1 开发环境

开发机:

Windows
macOS
Linux

本地服务:

PostgreSQL
Redis
License API
Admin Console

推荐全部使用 Docker。

3.2 Staging

建议单独建立:

staging.example.com

环境:

API
PostgreSQL
Redis
Admin
Payment Sandbox

用于:

功能测试
升级测试
Migration测试
支付Webhook测试
License并发测试

3.3 Production

生产环境:

api.example.com
admin.example.com
app.example.com
download.example.com
status.example.com

生产数据库:

PostgreSQL

生产缓存:

Redis

4. 环境变量管理

禁止把生产密钥提交到 Git。

错误:

.env
appsettings.Production.json

直接提交:

git add .
git commit

正确:

Git

    ├── Source Code
    └── Configuration Template

Production

    └── Secret Manager

5. 环境变量分类

建议:

Database
Redis
JWT
License Signing
Payment
Email
Cloud Storage
Monitoring

例如:

POSTGRES_HOST=postgres
POSTGRES_DATABASE=license
POSTGRES_USERNAME=license
POSTGRES_PASSWORD=

REDIS_HOST=redis
REDIS_PASSWORD=

PAYMENT_SECRET=
PAYMENT_WEBHOOK_SECRET=

SMTP_HOST=
SMTP_USERNAME=
SMTP_PASSWORD=

LICENSE_SIGNING_KEY=

6. Secret Management

开发环境:

.env

Staging:

GitHub Actions Secrets

Production:

优先:

Cloud Secret Manager

或者:

HashiCorp Vault

大型商业部署:

KMS / HSM

7. License私钥管理

这是整个系统最重要的Secret之一。

例如:

License Signing Private Key

禁止:

❌ Git
❌ Docker Image
❌ Source Code
❌ Client
❌ Public Download

正确:

License Server


Secret Manager / KMS


Private Key

客户端只保存:

Public Key

8. PostgreSQL生产配置

生产数据库:

不开放公网

Docker网络:

license_network

只有:

License API
Worker
Admin Backend

可以连接数据库。

禁止:

0.0.0.0:5432

9. PostgreSQL连接池

ASP.NET Core配置:

Maximum Pool Size
Minimum Pool Size
Connection Timeout
Command Timeout

不要无限增加连接数。

服务器:

2 CPU / 4GB RAM

可以从较小连接池开始,根据压力测试调整。

10. Redis生产配置

Redis用于:

Rate Limiting
Distributed Cache
Session
Temporary Data
Idempotency
Distributed Lock

Redis同样:

❌ 不开放公网

11. Redis数据原则

不要把唯一重要数据只放Redis。

错误:

License

Redis

正确:

License

PostgreSQL

Cache

Redis

Redis丢失后:

系统可以重新从PostgreSQL恢复

12. Admin Console部署

Next.js项目:

apps/admin-console

构建:

bun install
bun run build

Docker:

docker build -t license-admin .

运行:

Browser

Nginx

Next.js

License API

Admin不要直接访问PostgreSQL。

13. Customer Portal部署

Customer Portal:

app.example.com

用户可以:

Login
View License
View Orders
View Devices
Deactivate Device
Download Software
View Subscription

同样:

Customer Portal

License API

PostgreSQL

14. Admin权限

至少划分:

SuperAdmin
Admin
Support
Finance
Developer
ReadOnly

例如:

SuperAdmin

    ├── License
    ├── Users
    ├── Orders
    ├── Payments
    ├── System
    └── Security

Support:

License查询
Customer查询
Device管理

但不能:

查看Signing Private Key
修改系统Security配置

15. Admin MFA

生产环境:

Admin Login

Password

MFA

Session

推荐:

TOTP
Passkey
Security Key

禁止Admin仅依赖:

Username + Password

16. Payment部署

支付流程:

Customer

Checkout

Payment Provider

Payment Success

Webhook

License Server

Create License

Email

重点:

不要根据浏览器跳转页面判断支付成功。

必须以:

Verified Webhook

作为最终依据。

17. Webhook安全

Webhook必须验证:

Signature
Timestamp
Event ID

同时保存:

WebhookEvent

建立:

Unique(EventId)

防止:

同一个Webhook
重复处理

18. 支付幂等性

例如:

Payment Success

Webhook发送三次:

Webhook #1
Webhook #2
Webhook #3

系统最终只能:

创建一个Order
创建一个License
发送一次激活邮件

不能:

创建三个License

19. 自动发货

订单状态:

Pending

Paid

LicenseCreated

EmailQueued

Delivered

邮件:

Your Order
License Key
Download Link
Activation Guide

邮件发送失败:

Retry

而不是重新创建License。

20. Email Worker

推荐后台Worker:

Email Queue

Email Worker

SMTP / Email Provider

API不要:

HTTP Request

等待SMTP

返回用户

应该:

API

Queue

立即返回

Worker

发送Email

21. Background Worker

推荐:

License.Worker

处理:

Email
Payment
Cleanup
Expiration
Device
Update
Notification

这样API和后台任务职责分离。

22. License过期任务

Worker周期执行:

Every 5 minutes

检查:

ExpiresAt

状态:

Active

Expired

但是不要依赖Worker判断授权是否有效。

API本身仍然必须检查:

ExpiresAt

Worker只是:

状态维护
通知
清理

23. 自动更新服务器

建立:

download.example.com

目录:

releases/
├── windows/
├── macos/
└── linux/

每个版本:

v1.0.0
v1.0.1
v1.1.0

同时提供:

manifest.json

包含:

Version
Platform
Download
SHA256
Signature

24. Release安全

发布流程:

Build

Test

Generate SHA256

Code Sign

Generate Release Signature

Upload

Publish

客户端:

Download

Hash Verify

Signature Verify

Install

25. Monitoring

生产部署:

Prometheus
Grafana
Loki
OpenTelemetry

最少监控:

API Availability
API Latency
HTTP 5xx
Database
Redis
CPU
Memory
Disk

26. License业务监控

额外监控:

Activation Success
Activation Failure
Device Limit
License Expired
License Revoked
Payment Failure
Webhook Failure

例如:

Activation Failure Rate

突然从:

1%

变成:

20%

应该立即报警。

27. 日志

日志必须包含:

Timestamp
RequestId
UserId
LicenseId
DeviceId
Action
Result

但是:

❌ License完整密钥
❌ Password
❌ API Secret
❌ Payment Secret
❌ Private Key

绝对不能写入日志。

28. Audit Log

重要Admin操作:

Create License
Revoke License
Reset Device
Refund Order
Change Plan
Change User Role
Change System Config

都记录:

Who
What
When
IP
Result

例如:

Admin:
admin@example.com

Action:
Revoke License

License:
LIC-xxxx

Time:
2026-08-11 12:30:00

Result:
Success

29. Backup

生产数据库:

Daily Full Backup
+
Continuous WAL / PITR

备份:

Local
+
Remote Object Storage

例如:

Server

Encrypted Backup

Object Storage

30. Backup测试

每月至少一次:

Backup

New PostgreSQL

Restore

Run API

Test License

必须验证:

License
Order
Customer
Device
Payment

都能恢复。

31. CI/CD

Git Push:

GitHub

GitHub Actions

Build

Test

Security Scan

Docker Build

Push Registry

生产:

Approval

Deploy

32. Docker Registry

推荐:

GHCR

镜像:

ghcr.io/company/license-server
ghcr.io/company/admin-console

版本:

v1.0.0
v1.0.1

同时可以:

latest

但生产部署优先使用:

固定版本

而不是:

latest

33. Production Deployment

标准流程:

git tag v1.0.1

CI Build

Tests

Docker Image

Registry

Backup

Database Migration

Deploy

Health Check

Smoke Test

34. 回滚

部署失败:

v1.0.1

回滚:

v1.0.0

Docker:

docker compose pull
docker compose up -d

使用固定版本:

license-server:v1.0.0

不要依赖:

latest

35. 数据库Migration回滚

数据库Migration必须考虑:

Backward Compatibility

推荐:

Expand

Deploy

Migrate Data

Switch

Contract

不要一次性删除旧字段。

36. Firewall

公网只允许:

80
443
22

如果SSH允许:

22

建议进一步限制来源IP。

绝对不要开放:

5432
6379

37. Docker安全

容器尽量:

Non-root
Read-only filesystem
No unnecessary capabilities
Resource Limits

例如:

CPU Limit
Memory Limit

防止异常程序耗尽整个服务器。

38. API Rate Limit

重点接口:

/login
/license/activate
/license/validate
/password/reset

必须限速。

例如:

IP
+
Account
+
License
+
Device

多维度限制。

39. 防爆破

激活码不能只依赖:

Rate Limit

还应该:

License Hash
+
Rate Limit
+
IP Reputation
+
Device Fingerprint
+
Audit

同时避免返回过于详细的错误:

错误:

License存在,但Device已经达到上限

在某些接口场景下可能泄露信息。

根据接口用途选择合适的错误粒度。

40. WAF

推荐:

Cloudflare

前面:

Cloudflare

WAF

Rate Limit

Nginx

ASP.NET Core

API服务器不要直接暴露给整个Internet,尽可能让入口集中到WAF/CDN层。

41. DDoS

基础:

Cloudflare

进一步:

Rate Limit
WAF
Caching
Origin Protection

License API一般不缓存敏感响应。

42. Production Security Checklist

☐ HTTPS
☐ HSTS
☐ WAF
☐ Rate Limit
☐ MFA
☐ RBAC
☐ Audit Log
☐ Secret Manager
☐ Database Private
☐ Redis Private
☐ Backup
☐ Restore Test
☐ Dependency Scan
☐ Container Scan
☐ Code Signing
☐ Update Signature
☐ Webhook Verification
☐ Idempotency
☐ Monitoring
☐ Alerting

43. 商业软件最终部署结构

最终:

                           Internet


                         Cloudflare

                    ┌─────────┴─────────┐
                    │                   │
                   WAF                DNS


                  Nginx

       ┌────────────┼─────────────┐
       │            │             │
       ▼            ▼             ▼
     API          Admin        Customer

       ├──────────────┐
       │              │
       ▼              ▼
 PostgreSQL         Redis


    Backup


 Object Storage

后台:

Worker
 ├── Payment
 ├── Email
 ├── License
 ├── Cleanup
 └── Notification

监控:

OpenTelemetry

       ├── Metrics → Prometheus
       ├── Logs → Loki
       └── Traces → Tempo


                   Grafana

44. 最终上线顺序

不要一次性全部上线。

建议:

Phase 1

PostgreSQL
Redis
ASP.NET Core

目标:

API正常
数据库正常
License正常

Phase 2

Admin Console
Customer Portal

Phase 3

Payment
Webhook
Email
Automatic Delivery

Phase 4

Nginx
HTTPS
Cloudflare
WAF

Phase 5

Backup
Monitoring
Alerting

Phase 6

CI/CD
Docker Registry
Automatic Deployment

Phase 7

Auto Update
Code Signing
Windows
macOS
Linux

Phase 8

Security Audit
Load Test
Disaster Recovery
Production Launch

45. 正式商业上线前最终Checklist

Infrastructure
☐ Server
☐ Domain
☐ DNS
☐ Firewall
☐ Docker

Backend
☐ ASP.NET Core
☐ PostgreSQL
☐ Redis
☐ EF Core Migration
☐ Background Worker

Frontend
☐ Admin Console
☐ Customer Portal
☐ Download Center

License
☐ Generate
☐ Activate
☐ Validate
☐ Revoke
☐ Expire
☐ Device Limit
☐ Offline Grace
☐ Signed Token

Payment
☐ Checkout
☐ Webhook
☐ Idempotency
☐ Refund
☐ Automatic License

Email
☐ SMTP/Provider
☐ Activation Email
☐ Password Reset
☐ Order Email

Security
☐ HTTPS
☐ WAF
☐ Rate Limit
☐ MFA
☐ RBAC
☐ Audit Log
☐ Secret Management
☐ Private Database

Client
☐ Windows
☐ macOS Intel
☐ macOS ARM64
☐ Linux
☐ Code Signing
☐ Auto Update

Operations
☐ Logs
☐ Metrics
☐ Traces
☐ Alerts
☐ Backup
☐ Restore
☐ Disaster Recovery

Release
☐ CI
☐ CD
☐ Docker Registry
☐ Version Tag
☐ Rollback
☐ Release Notes
☐ Documentation

Commercial
☐ Pricing
☐ Terms
☐ Privacy Policy
☐ Refund Policy
☐ Support
☐ Status Page

46. 推荐的项目文档目录

以后整个项目可以整理成:

docs/

├── 01-project-overview.md
├── 02-architecture.md
├── 03-development-environment.md
├── 04-database.md
├── 05-license-engine.md
├── 06-client-sdk.md
├── 07-admin-console.md
├── 08-payment.md
├── 09-security.md
├── 10-production-deployment.md
├── 11-production-extensions.md
├── 12-backup-recovery.md
├── 13-monitoring.md
├── 14-ci-cd.md
├── 15-client-release.md
├── 16-troubleshooting.md
└── 17-commercial-launch-checklist.md

这样以后开发到哪个阶段,就直接更新对应文档。

47. 直播部署时使用的最简版本

如果只是直播,不需要执行整个第十一部分。

直接:

cd /opt/license-platform

docker compose pull

docker compose up -d postgres redis

docker compose ps

docker compose up -d license-server

docker compose logs -f license-server

curl http://127.0.0.1:8080/health

然后:

Browser

https://api.example.com/health

ASP.NET Core

PostgreSQL + Redis

这一套就是你的“直播演示部署路径”。

后续正式商业上线,再按照本章逐步增加:

HTTPS
→ WAF
→ Admin
→ Payment
→ Email
→ Backup
→ Monitoring
→ CI/CD
→ Auto Update
→ Security Audit

这样既方便直播,又不会因为一开始部署几十个组件导致现场出现不可控的问题。

以后你开发到具体阶段时,可以直接把这一章继续拆成 “11.1 支付部署、11.2 邮件部署、11.3 监控部署、11.4 CI/CD部署……”,逐项补进去。

💬 评论区

💬 评论列表

⏳ 正在加载评论...

✍️ 留下评论

⏳ 正在加载用户状态...

页面活动热力图

(模拟热力图:红点代表活动强度)