Web 应用域名授权验证指南
域名验证功能用于保护 Web 应用,确保只有已授权的域名才能正常使用系统。适用于 SaaS 平台、网站系统等场景。
在管理后台添加域名
管理员在【域名管理】中添加需要授权的域名
应用启动时调用 API 验证
应用通过 API 验证当前域名是否已授权(需签名)
根据返回结果放行或拦截
验证通过则正常运行,失败则显示未授权提示
在【产品管理】列表中查看
示例: "1"
在【产品管理 → 编辑】中查看,48位字符串
用于 API 请求签名
每次请求必须包含
签名算法见集成文档
/api/domain-verify.php
验证域名是否已授权。请求方式为 POST + JSON,需携带签名。
请求参数:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| product_key | int | 必填 | 产品ID |
| timestamp | int | 必填 | 当前Unix时间戳(秒) |
| sign | string | 必填 | HMAC-SHA256签名(使用 secret_key) |
| domain | string | 必填 | 要验证的域名 |
域名授权成功返回:
{
"success": true,
"code": 0,
"message": "域名已授权",
"data": {
"domain": "example.com",
"authorized": true,
"code": "",
"expire_time": 1735689600
}
}
域名未授权返回:
{
"success": false,
"code": 403,
"message": "域名未授权",
"data": {
"domain": "example.com",
"authorized": false
}
}
域名已过期返回:
{
"success": false,
"code": 403,
"message": "域名授权已过期",
"data": {
"domain": "example.com",
"authorized": false,
"expire_time": 1735689600
}
}
域名验证同样需要 HMAC-SHA256 签名,算法与用户验证接口一致:
构建参数:{"product_key": 1, "timestamp": 1735600000, "domain": "example.com"}
过滤空值后按 key 字典序排列,拼接为:domain=example.com&product_key=1×tamp=1735600000
计算:HMAC-SHA256(secret_key, signStr) 得到签名字符串
将签名添加到请求的 sign 字段中
PHP 验证示例(服务端推荐):
<?php
/**
* 域名授权验证 - 放在应用入口文件开头
*/
function verifyDomainAuth() {
$apiUrl = 'https://your-domain.com/api/domain-verify.php';
$secretKey = 'your_secret_key_48chars';
$productId = 1;
// 获取当前域名
$currentDomain = $_SERVER['HTTP_HOST'] ?? $_SERVER['SERVER_NAME'];
// 构建参数
$params = [
'product_key' => $productId,
'timestamp' => time(),
'domain' => $currentDomain,
];
// 生成签名
$filtered = [];
foreach ($params as $k => $v) {
if ($k === 'sign') continue;
if ($v !== null && $v !== '') {
$filtered[$k] = (string)$v;
}
}
ksort($filtered);
$signStr = implode('&', array_map(
fn($k, $v) => "$k=$v",
array_keys($filtered), $filtered
));
$params['sign'] = hash_hmac('sha256', $signStr, $secretKey);
// 发送请求
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $apiUrl);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($params));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 5);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
// 网络异常时放行(避免服务器宕机导致所有站点不可用)
if ($response === false || $httpCode !== 200) {
return true;
}
$result = json_decode($response, true);
return isset($result['success']) && $result['success'] === true;
}
// 在应用入口调用
if (!verifyDomainAuth()) {
http_response_code(403);
die('<h1>域名未授权</h1><p>请联系管理员获取授权</p>');
}
JavaScript/Node.js 验证示例:
/**
* 域名授权验证 - Node.js 服务端中间件
*/
async function verifyDomainAuth(secretKey, productId) {
const apiUrl = 'https://your-domain.com/api/domain-verify.php';
const currentDomain = process.env.HOST || 'example.com';
// 构建参数
const params = {
product_key: productId,
timestamp: Math.floor(Date.now() / 1000),
domain: currentDomain,
};
// 生成签名(Node.js)
const crypto = require('crypto');
const filtered = Object.entries(params)
.filter(([k, v]) => v !== null && v !== '')
.sort(([a], [b]) => a.localeCompare(b));
const signStr = filtered.map(([k, v]) => `${k}=${v}`).join('&');
params.sign = crypto
.createHmac('sha256', secretKey)
.update(signStr)
.digest('hex');
// 发送请求
try {
const response = await fetch(apiUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(params),
});
const result = await response.json();
return result.success === true;
} catch (error) {
// 网络异常时放行
return true;
}
}
// Express 中间件示例
app.use(async (req, res, next) => {
const authorized = await verifyDomainAuth(
'your_secret_key_48chars', 1
);
if (!authorized) {
return res.status(403).send('<h1>域名未授权</h1>');
}
next();
});
Python 验证示例:
import hashlib, hmac, time, json, urllib.request
def verify_domain():
api_url = 'https://your-domain.com/api/domain-verify.php'
secret_key = 'your_secret_key_48chars'
product_id = 1
domain = 'example.com' # 替换为当前域名
# 构建参数
params = {
'product_key': product_id,
'timestamp': int(time.time()),
'domain': domain,
}
# 生成签名
filtered = {k: str(v) for k, v in params.items() if v}
sign_str = '&'.join(f"{k}={v}" for k, v in sorted(filtered.items()))
sign = hmac.new(
secret_key.encode(), sign_str.encode(), hashlib.sha256
).hexdigest()
params['sign'] = sign
# 发送请求
try:
req = urllib.request.Request(
api_url,
data=json.dumps(params).encode(),
headers={'Content-Type': 'application/json'},
)
with urllib.request.urlopen(req, timeout=5) as resp:
result = json.loads(resp.read())
return result.get('success', False)
except Exception:
return True # 网络异常时放行
if not verify_domain():
print("域名未授权")
exit(1)
product_key、timestamp、sign 三个公共参数
secret_key 仅存放在服务端,切勿暴露给前端或客户端