很多朋友问过我一个问题:我的网站是纯静态HTML页面,没有PHP环境,能加卡密验证吗?
答案是:可以。
而且比PHP方案还简单——不需要服务器环境、不需要配置数据库,只需要把一段JavaScript代码复制到你的HTML文件里,上传到服务器就能用。
用户访问页面时,会自动弹出卡密验证框,输入正确的卡密才能看到内容。
一、适用场景
这套纯前端方案适合以下情况:
-
网站是纯静态HTML,没有PHP/ASP/JSP等后端环境
-
只想保护某个特定页面,比如VIP下载页、付费文档页
-
网站托管在对象存储(OSS/COS)上,不支持PHP
-
不想折腾后端,想5分钟快速搞定
二、接入步骤
第一步:去卡密通官网(keyt.cn)免费注册一个账号,创建一个应用,获取API地址和应用名称。
第二步:把下面的完整代码复制到你的HTML文件中,放在 </body> 标签之前。
第三步:修改代码顶部的 API_URL 和 APP_NAME 为你的信息。
上传到服务器,完事。
三、完整代码
<script src="https://cdn.jsdelivr.net/npm/crypto-js@4.2.0/crypto-js.min.js">
</script>
<script>
// ============================================================
// 配置区(改成你自己的)
// ============================================================
var CONFIG = {
API_URL: 'https://www.keyt.cn/kami/你的账号/check.php',
APP_NAME: '你的应用名'
};
// ============================================================
if (localStorage.getItem('card_verified') === 'true') {
// ===== 已登录,显示剩余时间悬浮窗 =====
(function() {
var remainDiv = document.createElement('div');
remainDiv.id = 'remainTimeDisplay';
remainDiv.style.cssText = 'position:fixed;top:16px;right:20px;background:rgba(0,0,0,0.75);backdrop-filter:blur(8px);color:#36d399;padding:8px 18px;border-radius:10px;font-size:14px;z-index:9999;font-family:sans-serif;border:1px solid rgba(255,255,255,0.08);box-shadow:0 4px 16px rgba(0,0,0,0.3);cursor:move;user-select:none;';
remainDiv.textContent = '⏱ 加载中…';
document.body.appendChild(remainDiv);
// 拖拽功能
var isDragging = false;
var offsetX, offsetY;
remainDiv.addEventListener('mousedown', function(e) {
isDragging = true;
var rect = remainDiv.getBoundingClientRect();
offsetX = e.clientX – rect.left;
offsetY = e.clientY – rect.top;
remainDiv.style.cursor = 'grabbing';
remainDiv.style.transition = 'none';
e.preventDefault();
});
document.addEventListener('mousemove', function(e) {
if (!isDragging) return;
var x = e.clientX – offsetX;
var y = e.clientY – offsetY;
x = Math.max(0, Math.min(window.innerWidth – remainDiv.offsetWidth, x));
y = Math.max(0, Math.min(window.innerHeight – remainDiv.offsetHeight, y));
remainDiv.style.left = x + 'px';
remainDiv.style.top = y + 'px';
remainDiv.style.right = 'auto';
});
document.addEventListener('mouseup', function() {
if (isDragging) {
isDragging = false;
remainDiv.style.cursor = 'move';
}
});
function getCookie(name) {
var match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)'));
if (match) return match[2];
return null;
}
function deleteCookie(name) {
document.cookie = name + '=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;';
}
function request(url, callback) {
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
callback(xhr.status === 200 ? xhr.responseText : 'error');
}
};
xhr.send();
}
function getDeviceId() {
var saved = localStorage.getItem('device_id');
if (saved) return saved;
var parts = [screen.width + 'x' + screen.height, screen.colorDepth, navigator.platform, navigator.userAgent];
try {
var c = document.createElement('canvas');
c.width = 256;
c.height = 64;
var ctx = c.getContext('2d');
ctx.fillStyle = '#f60';
ctx.fillRect(100, 1, 62, 20);
ctx.fillStyle = '#069';
ctx.font = '14px Arial';
ctx.fillText('Keyt.cn', 2, 15);
parts.push(c.toDataURL());
} catch(e) {}
var id = 'web_' + CryptoJS.MD5(parts.join('|')).toString();
localStorage.setItem('device_id', id);
return id;
}
function doHeartbeat() {
var card = getCookie('card');
if (!card) return;
var deviceId = getDeviceId();
var url = CONFIG.API_URL + '?card=' + encodeURIComponent(card) + '&mac=' + encodeURIComponent(deviceId) + '&app=' + CONFIG.APP_NAME;
request(url, function(response) {
var pos = response.indexOf('|sign=');
if (pos !== -1) response = response.substring(0, pos);
var parts = response.split('|');
if (parts[0] === 'ok') {
var days = parts[2] || '未知';
var minutes = parseInt(parts[3]) || 0;
localStorage.setItem('remain_days', days);
localStorage.setItem('remain_minutes', minutes);
var el = document.getElementById('remainTimeDisplay');
if (!el) return;
if (days === '永久') {
el.textContent = '⏱ 永久有效';
el.style.color = '#36d399';
return;
}
if (minutes <= 0) {
el.textContent = '⏱ 卡密已过期';
el.style.color = '#ff6b6b';
return;
}
var daysNum = Math.floor(minutes / 1440);
var hours = Math.floor((minutes % 1440) / 60);
var mins = minutes % 60;
var text = '';
if (daysNum > 0) text += daysNum + '天';
if (hours > 0) text += hours + '小时';
if (mins > 0) text += mins + '分钟';
el.textContent = '⏱ 剩余时间:' + text;
el.style.color = '#36d399';
} else {
clearInterval(heartTimer);
alert('卡密已失效,请重新验证');
deleteCookie('card');
localStorage.removeItem('card_verified');
localStorage.removeItem('remain_days');
localStorage.removeItem('remain_minutes');
var remainEl = document.getElementById('remainTimeDisplay');
if (remainEl) remainEl.remove();
document.getElementById('authBox').style.display = 'flex';
}
});
}
// 启动心跳(60秒一次)
var heartTimer = setInterval(doHeartbeat, 60000);
setTimeout(doHeartbeat, 2000);
})();
} else {
// ===== 弹出验证框 =====
document.write('<div id="authBox" style="position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.92);z-index:999999;display:flex;align-items:center;justify-content:center;font-family:sans-serif;">');
document.write('<div style="background:#1a202c;padding:40px;border-radius:20px;width:400px;max-width:90%;text-align:center;color:#fff;box-shadow:0 20px 60px rgba(0,0,0,0.5);border:1px solid rgba(255,255,255,0.06);">');
document.write('<div style="font-size:56px;margin-bottom:12px;">🔐</div>');
document.write('<h2 style="font-size:24px;margin-bottom:4px;font-weight:700;">请输入卡密</h2>');
document.write('<p style="color:#94a3b8;font-size:14px;margin-bottom:24px;">验证通过后才能查看内容</p>');
document.write('<div id="remainTime" style="color:#36d399;font-size:14px;margin-bottom:12px;"></div>');
document.write('<input id="cardInput" type="text" placeholder="请输入卡密" style="width:100%;padding:14px 18px;border:2px solid #2d3748;border-radius:12px;background:#111827;color:#fff;font-size:16px;text-align:center;letter-spacing:2px;outline:none;font-family:monospace;box-sizing:border-box;">');
document.write('<div id="authError" style="color:#ff6b6b;font-size:13px;margin-top:8px;min-height:20px;"></div>');
document.write('<button id="verifyBtn" style="width:100%;padding:14px 0;border:none;border-radius:12px;font-size:16px;font-weight:600;color:#000;background:linear-gradient(90deg,#4096ff,#36d399);cursor:pointer;margin-top:16px;">验证卡密</button>');
document.write('</div></div>');
function getDeviceId() {
var saved = localStorage.getItem('device_id');
if (saved) return saved;
var parts = [screen.width + 'x' + screen.height, screen.colorDepth, navigator.platform, navigator.userAgent];
try {
var c = document.createElement('canvas');
c.width = 256;
c.height = 64;
var ctx = c.getContext('2d');
ctx.fillStyle = '#f60';
ctx.fillRect(100, 1, 62, 20);
ctx.fillStyle = '#069';
ctx.font = '14px Arial';
ctx.fillText('Keyt.cn', 2, 15);
parts.push(c.toDataURL());
} catch(e) {}
var id = 'web_' + CryptoJS.MD5(parts.join('|')).toString();
localStorage.setItem('device_id', id);
return id;
}
document.getElementById('verifyBtn').onclick = function() {
var card = document.getElementById('cardInput').value.trim();
if (!card) { document.getElementById('authError').textContent = '请输入卡密'; return; }
document.getElementById('authError').textContent = '';
this.disabled = true;
this.textContent = '验证中…';
var deviceId = getDeviceId();
var xhr = new XMLHttpRequest();
xhr.open('GET', CONFIG.API_URL + '?card=' + encodeURIComponent(card) + '&mac=' + encodeURIComponent(deviceId) + '&app=' + CONFIG.APP_NAME);
xhr.onload = function() {
var r = xhr.responseText;
var p = r.indexOf('|sign=');
if (p !== -1) r = r.substring(0, p);
var parts = r.split('|');
if (parts[0] === 'ok') {
var days = parts[2] || '未知';
var minutes = parseInt(parts[3]) || 0;
document.cookie = 'card=' + encodeURIComponent(card) + '; path=/; max-age=' + (30 * 24 * 60 * 60);
localStorage.setItem('card_verified', 'true');
localStorage.setItem('remain_days', days);
localStorage.setItem('remain_minutes', minutes);
document.getElementById('authBox').style.display = 'none';
location.reload();
} else {
var msgs = {
'invalid_card': '卡密无效,请检查是否输入正确',
'expired': '卡密已过期',
'banned': '卡密已被禁用',
'device_mismatch': '设备不匹配',
'online_limit_reached': '在线设备数已满',
'too_frequent': '验证过于频繁,请稍后再试'
};
document.getElementById('authError').textContent = msgs[parts[1]] || '验证失败';
document.getElementById('verifyBtn').disabled = false;
document.getElementById('verifyBtn').textContent = '验证卡密';
}
};
xhr.send();
};
// Enter键提交
document.getElementById('cardInput').addEventListener('keydown', function(e) {
if (e.key === 'Enter') document.getElementById('verifyBtn').click();
});
// 自动验证已保存的卡密
var savedCard = document.cookie.match(new RegExp('(^| )card=([^;]+)'));
if (savedCard) {
document.getElementById('verifyBtn').textContent = '自动验证中…';
document.getElementById('verifyBtn').disabled = true;
var deviceId = getDeviceId();
var xhr2 = new XMLHttpRequest();
xhr2.open('GET', CONFIG.API_URL + '?card=' + encodeURIComponent(savedCard[2]) + '&mac=' + encodeURIComponent(deviceId) + '&app=' + CONFIG.APP_NAME);
xhr2.onload = function() {
var r = xhr2.responseText;
var p = r.indexOf('|sign=');
if (p !== -1) r = r.substring(0, p);
if (r.split('|')[0] === 'ok') {
var parts = r.split('|');
var days = parts[2] || '未知';
var minutes = parseInt(parts[3]) || 0;
localStorage.setItem('card_verified', 'true');
localStorage.setItem('remain_days', days);
localStorage.setItem('remain_minutes', minutes);
document.getElementById('authBox').style.display = 'none';
location.reload();
} else {
document.getElementById('verifyBtn').textContent = '验证卡密';
document.getElementById('verifyBtn').disabled = false;
document.getElementById('authError').textContent = '已保存的卡密已失效,请重新输入';
}
};
xhr2.send();
}
}
</script>
四、功能说明
| 卡密验证 | 用户输入卡密,调用API验证 |
| 设备指纹 | 基于Canvas生成设备唯一标识 |
| Cookie记忆 | 验证后记录状态,下次访问自动登录 |
| 剩余时间悬浮窗 | 右上角显示剩余时间,可拖拽移动 |
| 心跳保活 | 每60秒自动验证,卡密过期自动踢出 |
五、后台管理
注册卡密验证平台后,你会获得一个管理后台,可以:
-
批量生成卡密:天卡/周卡/月卡/季卡/年卡/终身卡
-
查看卡密状态:未使用/已激活/已过期/已禁用
-
禁用/启用卡密:随时控制某张卡密是否有效
-
使用记录:查看谁在什么时间用了哪张卡密
六、总结
HTML静态网页加卡密验证,纯前端方案最省事:
注册平台账号,获取API信息
复制代码到HTML文件,修改配置
上传服务器,完事
整个接入过程不超过10分钟,不需要后端环境,不需要数据库,适合纯静态网站。
想要更详细接入教程的话,可以搜索一下卡密通看看官网文档。

