授权验证 安全
TextPress 提供完整的授权验证 API,帮助开发者保护知识产权,实现正版授权验证。
授权码验证
验证用户授权码是否有效
域名绑定
支持多域名授权管理
有效期管理
支持永久或限时授权
实时验证
支持 CORS 跨域请求
授权验证流程
用户购买产品后获得授权码,在产品中配置授权码和域名,产品启动时调用 API 验证授权状态。
用户购买产品
用户在平台购买你的主题或插件,系统自动生成唯一授权码
绑定使用域名
用户在个人中心绑定要使用产品的域名(支持多个域名)
配置授权码
用户在产品后台设置中填入授权码
验证授权
产品调用 API 验证授权码和域名是否匹配
验证授权接口
/api/license/verify
验证授权码是否有效,支持 GET 和 POST 两种请求方式。
请求参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
license_key | string | 是 | 用户购买后获得的授权码 |
domain | string | 是 | 当前使用的域名 |
product_slug | string | 否 | 产品标识,用于验证授权码是否匹配特定产品 |
请求示例
GET /api/license/verify?license_key=XXXX-XXXX-XXXX-XXXX&domain=example.com&product_slug=my-theme
成功响应
{
"valid": true,
"code": "SUCCESS",
"message": "授权有效",
"license": {
"product": "My Theme",
"product_slug": "my-theme",
"version": "v1.2.0",
"domain": "example.com",
"domains": ["example.com", "dev.example.com"],
"max_domains": 3,
"expires_at": "2025-12-31 23:59:59",
"created_at": "2024-01-01 00:00:00"
}
}
错误响应
{
"valid": false,
"code": "DOMAIN_NOT_AUTHORIZED",
"message": "域名未授权",
"authorized_domains": ["other-domain.com"],
"max_domains": 3
}
响应字段说明
| 字段 | 类型 | 说明 |
|---|---|---|
valid | boolean | 授权是否有效 |
code | string | 状态码,用于程序判断 |
message | string | 提示信息,可直接展示给用户 |
license | object | 授权详情(仅当 valid=true 时返回) |
license.product | string | 产品名称 |
license.product_slug | string | 产品标识 |
license.version | string | 产品最新版本 |
license.domain | string | 当前验证的域名 |
license.domains | array | 已授权的所有域名 |
license.max_domains | int | 最大可绑定域名数 |
license.expires_at | string | 授权到期时间,"永久" 表示永不过期 |
批量检查授权接口
/api/license/check
检查指定域名是否拥有某些产品的授权,用于市场安装判断。
请求参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
domain | string | 是 | 要检查的域名 |
product_ids | string/array | 否 | 产品ID列表,逗号分隔或数组,不传则返回该域名所有授权 |
请求示例
GET /api/license/check?domain=example.com&product_ids=1,2,3
响应示例
{
"success": true,
"domain": "example.com",
"authorized_products": [1, 3],
"licenses": {
"1": {
"product_id": 1,
"product_name": "Premium Theme",
"product_slug": "premium-theme",
"version": "v1.2.0",
"download_url": "https://example.com/uploads/products/1/premium-theme.zip",
"license_key": "XXXX-XXXX-XXXX-XXXX",
"expires_at": "2025-12-31 23:59:59"
},
"3": {
"product_id": 3,
"product_name": "Pro Plugin",
"product_slug": "pro-plugin",
"version": "v2.0.0",
"download_url": "https://example.com/uploads/products/3/pro-plugin.zip",
"license_key": "YYYY-YYYY-YYYY-YYYY",
"expires_at": "永久"
}
}
}
使用场景
此接口主要用于市场功能,在加载市场列表时检查当前域名是否已购买某些付费产品,如果已授权则显示"安装"按钮而非"购买"按钮。
// 检查付费产品的授权状态
async function checkLicenses(productIds) {
const url = new URL('https://textpress.cn/api/license/check');
url.searchParams.set('domain', window.location.hostname);
url.searchParams.set('product_ids', productIds.join(','));
const response = await fetch(url.toString());
const data = await response.json();
if (data.success) {
// data.authorized_products 包含已授权的产品ID
// data.licenses 包含授权详情和下载地址
return data.licenses;
}
return {};
}
错误码说明
当 valid 为 false 时,请根据 code 字段判断具体错误类型并给用户友好提示。
| 错误码 | 说明 | 处理建议 |
|---|---|---|
SUCCESS | 验证成功 | 授权有效,正常使用 |
MISSING_LICENSE_KEY | 缺少授权码参数 | 提示用户输入授权码 |
MISSING_DOMAIN | 缺少域名参数 | 自动获取当前域名后重试 |
INVALID_LICENSE | 授权码无效 | 提示用户检查授权码是否正确 |
LICENSE_EXPIRED | 授权已过期 | 提示用户续费,可提供续费链接 |
LICENSE_REVOKED | 授权已被撤销 | 提示联系客服处理 |
PRODUCT_MISMATCH | 授权码与产品不匹配 | 检查是否使用了正确的授权码 |
DOMAIN_NOT_AUTHORIZED | 域名未授权 | 提示用户在用户中心绑定当前域名 |
集成示例
以下是在你的主题或插件中集成授权验证的完整示例代码:
<?php
/**
* 授权验证类 - 完整实现
*/
class LicenseManager {
private $apiUrl = 'https://textpress.cn/api/license/verify';
private $productSlug = 'my-theme';
private $cacheFile;
private $cacheTime = 86400; // 24小时
public function __construct() {
$this->cacheFile = __DIR__ . '/.license_cache';
}
/**
* 验证授权
*/
public function verify($licenseKey) {
// 先检查缓存
$cached = $this->getCache($licenseKey);
if ($cached !== false) {
return $cached;
}
// 调用 API 验证
$result = $this->callApi($licenseKey);
// 缓存结果
if ($result) {
$this->setCache($licenseKey, $result);
}
return $result;
}
/**
* 调用验证 API
*/
private function callApi($licenseKey) {
$params = [
'license_key' => $licenseKey,
'domain' => $_SERVER['HTTP_HOST'],
'product_slug' => $this->productSlug
];
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $this->apiUrl . '?' . http_build_query($params),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 10,
CURLOPT_SSL_VERIFYPEER => true,
CURLOPT_HTTPHEADER => ['Accept: application/json']
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode !== 200 || !$response) {
return ['valid' => false, 'code' => 'NETWORK_ERROR', 'message' => '网络请求失败'];
}
return json_decode($response, true);
}
/**
* 获取缓存
*/
private function getCache($licenseKey) {
if (!file_exists($this->cacheFile)) return false;
$data = json_decode(file_get_contents($this->cacheFile), true);
if (!$data || $data['key'] !== md5($licenseKey)) return false;
if (time() - $data['time'] > $this->cacheTime) return false;
return $data['result'];
}
/**
* 设置缓存
*/
private function setCache($licenseKey, $result) {
$data = [
'key' => md5($licenseKey),
'time' => time(),
'result' => $result
];
file_put_contents($this->cacheFile, json_encode($data));
}
/**
* 清除缓存
*/
public function clearCache() {
if (file_exists($this->cacheFile)) {
unlink($this->cacheFile);
}
}
}
// 使用示例
$license = new LicenseManager();
$result = $license->verify('XXXX-XXXX-XXXX-XXXX');
if ($result['valid']) {
echo '授权有效,到期时间:' . $result['license']['expires_at'];
} else {
echo '授权无效:' . $result['message'];
}
/**
* 授权验证模块
*/
const LicenseManager = {
apiUrl: 'https://textpress.cn/api/license/verify',
productSlug: 'my-theme',
cacheKey: 'license_cache',
cacheTime: 24 * 60 * 60 * 1000, // 24小时
// 验证授权
async verify(licenseKey) {
// 检查缓存
const cached = this.getCache(licenseKey);
if (cached) return cached;
// 调用 API
try {
const params = new URLSearchParams({
license_key: licenseKey,
domain: window.location.hostname,
product_slug: this.productSlug
});
const response = await fetch(`${this.apiUrl}?${params}`);
const data = await response.json();
// 缓存结果
this.setCache(licenseKey, data);
return data;
} catch (error) {
console.error('授权验证失败:', error);
return { valid: false, code: 'NETWORK_ERROR', message: '网络请求失败' };
}
},
// 获取缓存
getCache(licenseKey) {
try {
const data = JSON.parse(localStorage.getItem(this.cacheKey));
if (!data || data.key !== this.hash(licenseKey)) return null;
if (Date.now() - data.time > this.cacheTime) return null;
return data.result;
} catch {
return null;
}
},
// 设置缓存
setCache(licenseKey, result) {
localStorage.setItem(this.cacheKey, JSON.stringify({
key: this.hash(licenseKey),
time: Date.now(),
result
}));
},
// 简单哈希
hash(str) {
let hash = 0;
for (let i = 0; i < str.length; i++) {
hash = ((hash << 5) - hash) + str.charCodeAt(i);
hash |= 0;
}
return hash.toString(16);
},
// 显示错误提示
showError(data) {
const messages = {
'INVALID_LICENSE': '授权码无效,请检查是否输入正确',
'LICENSE_EXPIRED': '授权已过期,请续费后继续使用',
'DOMAIN_NOT_AUTHORIZED': '当前域名未授权,请在用户中心绑定域名',
'NETWORK_ERROR': '网络连接失败,请检查网络后重试'
};
alert(messages[data.code] || data.message);
}
};
// 使用示例
async function checkLicense() {
const result = await LicenseManager.verify('XXXX-XXXX-XXXX-XXXX');
if (result.valid) {
console.log('授权有效', result.license);
} else {
LicenseManager.showError(result);
}
}
<?php
/**
* WordPress 主题/插件授权验证
*/
// 添加设置页面
add_action('admin_menu', function() {
add_options_page('授权管理', '授权管理', 'manage_options', 'license-settings', 'render_license_page');
});
// 渲染设置页面
function render_license_page() {
if (isset($_POST['license_key'])) {
update_option('my_theme_license', sanitize_text_field($_POST['license_key']));
delete_transient('my_theme_license_check');
echo '<div class="notice notice-success"><p>授权码已保存</p></div>';
}
$license = get_option('my_theme_license', '');
$status = verify_license_status();
?>
<div class="wrap">
<h1>授权管理</h1>
<form method="post">
<table class="form-table">
<tr>
<th>授权码</th>
<td>
<input type="text" name="license_key" value="<?= esc_attr($license) ?>" class="regular-text">
<p class="description">请输入购买时获得的授权码</p>
</td>
</tr>
<tr>
<th>授权状态</th>
<td>
<?php if ($status['valid']): ?>
<span style="color:green">已授权</span>
- 到期时间:<?= $status['license']['expires_at'] ?>
<?php else: ?>
<span style="color:red">未授权</span>
- <?= $status['message'] ?>
<?php endif; ?>
</td>
</tr>
</table>
<?php submit_button('保存授权码'); ?>
</form>
</div>
<?php
}
// 验证授权状态
function verify_license_status() {
$license = get_option('my_theme_license', '');
if (!$license) {
return ['valid' => false, 'code' => 'NO_LICENSE', 'message' => '请输入授权码'];
}
// 使用 transient 缓存
$cached = get_transient('my_theme_license_check');
if ($cached !== false) return $cached;
// 调用 API
$response = wp_remote_get('https://textpress.cn/api/license/verify?' . http_build_query([
'license_key' => $license,
'domain' => $_SERVER['HTTP_HOST'],
'product_slug' => 'my-theme'
]));
if (is_wp_error($response)) {
return ['valid' => false, 'code' => 'NETWORK_ERROR', 'message' => '网络请求失败'];
}
$result = json_decode(wp_remote_retrieve_body($response), true);
set_transient('my_theme_license_check', $result, DAY_IN_SECONDS);
return $result;
}
// 在后台显示授权提示
add_action('admin_notices', function() {
$status = verify_license_status();
if (!$status['valid']) {
echo '<div class="notice notice-warning"><p>主题未授权:' . esc_html($status['message']) .
' <a href="' . admin_url('options-general.php?page=license-settings') . '">去授权</a></p></div>';
}
});
最佳实践
缓存验证结果
将结果缓存 24 小时,减少 API 调用,提升性能
优雅降级
网络失败时使用缓存结果,避免影响用户体验
友好提示
给用户清晰的错误提示和解决方案
安全存储
授权码存数据库,不要硬编码在代码中
安全建议
授权验证应在服务端进行,不要仅依赖前端验证。前端验证可以作为用户体验优化,但核心功能限制必须在服务端实现。
服务端验证
核心功能的授权检查必须在服务端进行,前端验证容易被绕过
HTTPS 传输
确保 API 请求使用 HTTPS,防止授权码在传输过程中被截获
隐藏授权码
在前端展示时对授权码进行脱敏处理,如只显示前后几位
定期验证
建议每天验证一次,及时发现授权状态变化
常见问题
授权验证失败但网络正常?
A: 请检查:1) 授权码是否正确;2) 当前域名是否已在用户中心绑定;3) 授权是否已过期。
如何支持本地开发环境?
A: 可以将 localhost 或本地 IP 添加到授权域名中,或在开发环境跳过验证。
API 请求超时怎么办?
A: 建议设置合理的超时时间(如 10 秒),超时后使用缓存结果或允许临时使用。
可以同时在多个域名使用吗?
A: 取决于授权类型,响应中的 max_domains 字段表示最大可绑定域名数。