Реализация лицензирования программного обеспечения через сайт
Продажа лицензий на ПО через сайт включает: генерацию лицензионных ключей после оплаты, активацию и привязку к устройству, проверку лицензии в приложении, управление подписками и обновление версий.
Модели лицензирования
| Модель | Описание | Технически |
|---|---|---|
| Perpetual | Единоразовая покупка версии | Ключ без срока, без онлайн-проверки |
| Subscription | Ежемесячная/годовая оплата | JWT-токен с expiry, онлайн-валидация |
| Per-seat | По количеству пользователей | Счётчик активаций на ключ |
| Node-locked | Привязка к конкретному устройству | HWID fingerprint |
Генерация лицензионных ключей
class LicenseKeyGenerator
{
private const CHARSET = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789';
public function generate(int $segments = 5, int $segmentLength = 5): string
{
$key = '';
for ($s = 0; $s < $segments; $s++) {
for ($c = 0; $c < $segmentLength; $c++) {
$key .= self::CHARSET[random_int(0, strlen(self::CHARSET) - 1)];
}
if ($s < $segments - 1) $key .= '-';
}
return $key; // Пример: A3K7M-XQ2WP-N8VLR-5HZTB-J4YCS
}
public function generateSigned(array $metadata): string
{
$base = $this->generate();
$hash = substr(hash_hmac('sha256', $base . json_encode($metadata), config('app.key')), 0, 8);
return $base . '-' . strtoupper($hash);
}
}
API активации лицензии
class LicenseController extends Controller
{
public function activate(Request $request): JsonResponse
{
$key = $request->input('license_key');
$hwid = $request->input('hardware_id');
$appVersion = $request->input('app_version');
$license = License::where('key', $key)->firstOrFail();
if ($license->status !== 'active') {
return response()->json(['error' => 'License is not active'], 403);
}
if ($license->expires_at && now()->isAfter($license->expires_at)) {
return response()->json(['error' => 'License expired'], 403);
}
// Проверка количества активаций
$activationCount = $license->activations()->where('revoked', false)->count();
if ($activationCount >= $license->max_activations) {
return response()->json(['error' => "Maximum activations ({$license->max_activations}) reached"], 403);
}
// Создаём активацию
$activation = $license->activations()->create([
'hardware_id' => $hwid,
'ip_address' => $request->ip(),
'app_version' => $appVersion,
'activated_at'=> now(),
]);
// Возвращаем JWT-токен лицензии
$token = JWT::encode([
'iss' => 'example.com',
'sub' => $license->id,
'exp' => $license->expires_at?->timestamp ?? PHP_INT_MAX,
'hwid' => $hwid,
'product' => $license->product_code,
'plan' => $license->plan,
], config('app.license_secret'), 'HS256');
return response()->json(['token' => $token, 'expires_at' => $license->expires_at]);
}
}
Онлайн-валидация лицензии в приложении
# В Python-приложении при каждом запуске
import jwt
import requests
from datetime import datetime
class LicenseValidator:
def __init__(self, license_key: str, hw_id: str):
self.license_key = license_key
self.hw_id = hw_id
self.token_cache_file = '.license_cache'
def validate(self) -> bool:
# Сначала проверяем кэшированный токен
cached = self._load_cached_token()
if cached and self._verify_token(cached):
return True
# Онлайн-активация
try:
resp = requests.post('https://api.example.com/v1/licenses/activate', {
'license_key': self.license_key,
'hardware_id': self.hw_id,
}, timeout=5)
if resp.status_code == 200:
token = resp.json()['token']
self._cache_token(token)
return self._verify_token(token)
except requests.exceptions.RequestException:
# Оффлайн-режим: используем кэш
return cached is not None
return False
def _verify_token(self, token: str) -> bool:
try:
payload = jwt.decode(token, LICENSE_PUBLIC_KEY, algorithms=['RS256'])
return payload.get('hwid') == self.hw_id
except jwt.ExpiredSignatureError:
return False
except jwt.InvalidTokenError:
return False
Интеграция с платёжной системой
// Webhook при успешной оплате
class HandleSuccessfulPayment
{
public function handle(PaymentSucceeded $event): void
{
$order = $event->order;
$product = $order->product;
for ($i = 0; $i < $order->quantity; $i++) {
License::create([
'order_id' => $order->id,
'product_code' => $product->code,
'key' => app(LicenseKeyGenerator::class)->generateSigned(['product' => $product->code]),
'plan' => $order->plan,
'max_activations' => $product->max_activations,
'expires_at' => $product->subscription_period
? now()->add($product->subscription_period)
: null,
'status' => 'active',
]);
}
Mail::to($order->customer_email)->send(new LicenseKeysMail($order));
}
}
Сроки
Система лицензирования с генерацией ключей, активацией и API-валидацией: 12–16 рабочих дней.







