对接教程
本章讲解如何把你的 WordPress 插件接入授权系统,从零开始实现一个完整的授权验证流程。学完本章你将掌握:
- WordPress 后台授权管理页面
- 授权码激活逻辑
- 运行时授权检查
- 7 天本地缓存策略
- 用户友好的过期/失效提示
1. 整体架构
WordPress 插件
├── admin/
│ └── partials/
│ └── license-page.php ← 后台授权管理页面
├── includes/
│ ├── class-license.php ← 授权核心类
│ └── class-admin.php ← 后台集成
└── assets/
├── css/admin.css
└── js/admin.js
2. 配置文件
在插件主文件里定义授权相关的常量:
<?php
// my-plugin/my-plugin.php
if (!defined('ABSPATH')) {
exit;
}
// 授权服务器地址(生产环境换成你的真实域名)
define('SHIGUANG_LICENSE_SERVER', 'https://license.example.com');
define('SHIGUANG_PRODUCT_SLUG', 'my-awesome-plugin');
// API 密钥(与 license-server 端 API_SECRET 一致)
if (!defined('SHIGUANG_API_SECRET')) {
define('SHIGUANG_API_SECRET', 'your-api-secret-32chars-min');
}
3. 授权核心类
封装所有授权相关逻辑:
<?php
// includes/class-license.php
class My_Plugin_License {
private static $instance = null;
public static function instance() {
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}
private function __construct() {
// 注册定时任务:清理过期授权
add_action('my_plugin_check_license_event', [$this, 'check_license']);
if (!wp_next_scheduled('my_plugin_check_license_event')) {
wp_schedule_event(time(), 'daily', 'my_plugin_check_license_event');
}
}
/**
* 标准化域名
*/
public static function normalize_domain($input) {
$domain = strtolower(trim($input));
$domain = preg_replace('#^https?://#', '', $domain);
if (($pos = strpos($domain, '/')) !== false) {
$domain = substr($domain, 0, $pos);
}
if (($pos = strpos($domain, ':')) !== false) {
$domain = substr($domain, 0, $pos);
}
$domain = preg_replace('#^www\.#', '', $domain);
return $domain;
}
/**
* 生成 API 签名
*/
public static function generate_signature($domain, $license_key, $serial = 1) {
$sign_data = $domain . '|' . $license_key . '|' . SHIGUANG_PRODUCT_SLUG . '|' . $serial;
return hash_hmac('sha256', $sign_data, SHIGUANG_API_SECRET);
}
/**
* 在线验证授权
* @param string $license_key
* @return array|false 成功返回授权信息,失败返回 false
*/
public function verify_online($license_key) {
$domain = self::normalize_domain(home_url());
$response = wp_remote_post(SHIGUANG_LICENSE_SERVER . '/api/verify.php', [
'body' => [
'license_key' => $license_key,
'domain' => $domain,
'product' => SHIGUANG_PRODUCT_SLUG,
'version' => MY_PLUGIN_VERSION,
'serial' => 1,
'signature' => self::generate_signature($domain, $license_key, 1),
],
'timeout' => 15,
]);
if (is_wp_error($response)) {
return new WP_Error('network_error', '网络错误:' . $response->get_error_message());
}
$body = wp_remote_retrieve_body($response);
$data = json_decode($body, true);
if (!$data || !isset($data['status'])) {
return new WP_Error('invalid_response', '服务器返回无效响应');
}
if ($data['status'] !== 'success') {
return new WP_Error('verify_failed', $data['message'] ?? '验证失败');
}
return $data;
}
/**
* 检查授权状态(带 7 天本地缓存)
*/
public function check_license() {
$license_key = get_option('my_plugin_license_key', '');
if (empty($license_key)) {
return ['status' => 'inactive', 'message' => '尚未激活授权'];
}
$cached = get_option('my_plugin_license_info', []);
// 检查缓存是否过期
$last_check = isset($cached['last_check']) ? strtotime($cached['last_check']) : 0;
$cache_age = time() - $last_check;
// 如果缓存有效(小于 7 天)且状态是 active,直接返回缓存
if ($cache_age < 7 * 86400 && ($cached['status'] ?? '') === 'active') {
// 但本地仍校验域名(防止服务器已解绑但缓存还在)
$current_domain = self::normalize_domain(home_url());
if (($cached['domain'] ?? '') !== $current_domain) {
return ['status' => 'domain_mismatch', 'message' => '授权域名不匹配'];
}
return $cached;
}
// 缓存过期或不存在 → 在线验证
$result = $this->verify_online($license_key);
if (is_wp_error($result)) {
// 在线验证失败,如果之前有 active 缓存,继续使用(容错)
if (($cached['status'] ?? '') === 'active') {
return $cached;
}
return ['status' => 'error', 'message' => $result->get_error_message()];
}
// 验证成功,更新缓存
$info = [
'status' => 'active',
'license_key' => $license_key,
'domain' => $result['license']['domain'],
'type' => $result['license']['type'],
'expires_at' => $result['license']['expires_at'],
'last_check' => date('Y-m-d H:i:s'),
];
update_option('my_plugin_license_info', $info);
return $info;
}
/**
* 激活授权码
*/
public function activate($license_key) {
$license_key = trim($license_key);
if (empty($license_key)) {
return new WP_Error('empty_key', '授权码不能为空');
}
$result = $this->verify_online($license_key);
if (is_wp_error($result)) {
return $result;
}
// 保存授权信息
update_option('my_plugin_license_key', $license_key);
update_option('my_plugin_license_info', [
'status' => 'active',
'license_key' => $license_key,
'domain' => $result['license']['domain'],
'type' => $result['license']['type'],
'expires_at' => $result['license']['expires_at'],
'last_check' => date('Y-m-d H:i:s'),
]);
return true;
}
/**
* 停用授权
*/
public function deactivate() {
delete_option('my_plugin_license_key');
delete_option('my_plugin_license_info');
}
/**
* 获取当前授权状态(简短版)
*/
public function is_licensed() {
$info = $this->check_license();
return ($info['status'] ?? '') === 'active';
}
}
4. 后台管理页面
<?php
// admin/partials/license-page.php
if (!current_user_can('manage_options')) {
wp_die('权限不足');
}
$license = My_Plugin_License::instance();
$info = $license->check_license();
$license_key = get_option('my_plugin_license_key', '');
?>
<div class="wrap my-plugin-license-page">
<h1>授权管理</h1>
<?php if (($info['status'] ?? '') === 'active'): ?>
<div class="notice notice-success">
<p><strong>✓ 授权已激活</strong></p>
</div>
<table class="form-table">
<tr>
<th>授权码</th>
<td><code><?php echo esc_html($license_key); ?></code></td>
</tr>
<tr>
<th>绑定域名</th>
<td><?php echo esc_html($info['domain'] ?? '-'); ?></td>
</tr>
<tr>
<th>授权类型</th>
<td><?php echo esc_html($info['type'] ?? 'standard'); ?></td>
</tr>
<tr>
<th>过期时间</th>
<td>
<?php
if (empty($info['expires_at'])) {
echo '永久';
} else {
echo esc_html($info['expires_at']);
}
?>
</td>
</tr>
</table>
<form method="post">
<?php wp_nonce_field('my_plugin_deactivate_license'); ?>
<button type="submit" name="action" value="deactivate" class="button">
停用授权
</button>
</form>
<?php else: ?>
<div class="notice notice-warning">
<p><strong>⚠ 尚未激活授权</strong></p>
</div>
<form method="post">
<?php wp_nonce_field('my_plugin_activate_license'); ?>
<table class="form-table">
<tr>
<th><label for="license_key">授权码</label></th>
<td>
<input type="text" name="license_key" id="license_key"
value="" class="regular-text"
placeholder="LIC-XXXXX-XXXXX-XXXXX-XXXXX">
<p class="description">
在 <a href="<?php echo esc_url(SHIGUANG_LICENSE_SERVER); ?>" target="_blank">
授权站</a> 购买后获取授权码
</p>
</td>
</tr>
</table>
<button type="submit" name="action" value="activate" class="button button-primary">
激活授权
</button>
</form>
<?php endif; ?>
</div>
<?php
// 处理表单提交
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
if ($_POST['action'] === 'activate') {
check_admin_referer('my_plugin_activate_license');
$result = $license->activate($_POST['license_key'] ?? '');
if (is_wp_error($result)) {
echo '<div class="notice notice-error"><p>' . esc_html($result->get_error_message()) . '</p></div>';
} else {
echo '<div class="notice notice-success"><p>授权激活成功!</p></div>';
echo '<script>location.reload();</script>';
}
} elseif ($_POST['action'] === 'deactivate') {
check_admin_referer('my_plugin_deactivate_license');
$license->deactivate();
echo '<script>location.reload();</script>';
}
}
?>
5. 插件功能 Gate
在关键功能执行前,验证授权:
<?php
// 在插件功能入口处检查
function my_plugin_some_feature() {
$license = My_Plugin_License::instance();
if (!$license->is_licensed()) {
wp_die(
'请先在「插件设置」中激活授权。',
'未授权',
['response' => 403, 'back_link' => true]
);
}
// 业务逻辑...
}
6. AJAX 端点:异步检查授权
前端 JavaScript 可以定期调用此接口检查授权是否还有效:
<?php
// includes/class-admin.php
add_action('wp_ajax_my_plugin_check_license', function () {
check_ajax_referer('my_plugin_admin', 'nonce');
$license = My_Plugin_License::instance();
$info = $license->check_license();
wp_send_json_success([
'is_licensed' => ($info['status'] ?? '') === 'active',
'info' => $info,
]);
});
前端 JS:
// assets/js/admin.js
jQuery.post(ajaxurl, {
action: 'my_plugin_check_license',
nonce: myPluginData.nonce
}, function(response) {
if (response.success && response.data.is_licensed) {
console.log('授权有效');
} else {
console.warn('授权无效');
}
});
下一步:查看 PHP 示例 了解完整的对接代码(包含测试代码)。