使用文档

时光授权系统文档

从快速开始到 API 对接,全面了解授权系统的使用与集成

对接教程

本章讲解如何把你的 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 示例 了解完整的对接代码(包含测试代码)。