101 lines
4.3 KiB
HTML
101 lines
4.3 KiB
HTML
<!DOCTYPE html>
|
||
<html>
|
||
<head>
|
||
<title>JWT Token 测试工具</title>
|
||
<style>
|
||
body { font-family: Arial, sans-serif; margin: 20px; }
|
||
.container { max-width: 800px; margin: 0 auto; }
|
||
textarea { width: 100%; height: 100px; margin: 10px 0; }
|
||
.result { background: #f5f5f5; padding: 15px; margin: 10px 0; border-radius: 5px; }
|
||
.error { background: #ffebee; color: #c62828; }
|
||
.success { background: #e8f5e8; color: #2e7d2e; }
|
||
button { padding: 10px 20px; background: #007bff; color: white; border: none; border-radius: 4px; cursor: pointer; }
|
||
button:hover { background: #0056b3; }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="container">
|
||
<h1>JWT Token 验证工具</h1>
|
||
|
||
<h3>步骤1: 从浏览器获取Token</h3>
|
||
<p>1. 登录你的应用</p>
|
||
<p>2. 打开开发者工具 → Application → Local Storage → 找到 'iMeetingUser'</p>
|
||
<p>3. 复制其中的 token 值到下面的文本框</p>
|
||
|
||
<textarea id="tokenInput" placeholder="在此粘贴JWT token..."></textarea>
|
||
<button onclick="decodeToken()">解码 JWT Token</button>
|
||
|
||
<div id="result"></div>
|
||
|
||
<h3>预期的JWT payload应该包含:</h3>
|
||
<ul>
|
||
<li><code>user_id</code>: 用户ID</li>
|
||
<li><code>username</code>: 用户名</li>
|
||
<li><code>caption</code>: 用户显示名</li>
|
||
<li><code>exp</code>: 过期时间戳</li>
|
||
<li><code>type</code>: "access"</li>
|
||
</ul>
|
||
</div>
|
||
|
||
<script>
|
||
function decodeToken() {
|
||
const token = document.getElementById('tokenInput').value.trim();
|
||
const resultDiv = document.getElementById('result');
|
||
|
||
if (!token) {
|
||
resultDiv.innerHTML = '<div class="result error">请输入JWT token</div>';
|
||
return;
|
||
}
|
||
|
||
try {
|
||
// JWT 由三部分组成,用 . 分隔
|
||
const parts = token.split('.');
|
||
if (parts.length !== 3) {
|
||
throw new Error('无效的JWT格式');
|
||
}
|
||
|
||
// 解码 header
|
||
const header = JSON.parse(atob(parts[0]));
|
||
|
||
// 解码 payload
|
||
const payload = JSON.parse(atob(parts[1]));
|
||
|
||
// 检查是否是我们的JWT
|
||
const isValidJWT = payload.type === 'access' &&
|
||
payload.user_id &&
|
||
payload.username &&
|
||
payload.exp;
|
||
|
||
const now = Math.floor(Date.now() / 1000);
|
||
const isExpired = payload.exp < now;
|
||
|
||
let resultHTML = '<div class="result ' + (isValidJWT ? 'success' : 'error') + '">';
|
||
resultHTML += '<h4>JWT 解码结果:</h4>';
|
||
resultHTML += '<p><strong>Header:</strong></p>';
|
||
resultHTML += '<pre>' + JSON.stringify(header, null, 2) + '</pre>';
|
||
resultHTML += '<p><strong>Payload:</strong></p>';
|
||
resultHTML += '<pre>' + JSON.stringify(payload, null, 2) + '</pre>';
|
||
|
||
if (isExpired) {
|
||
resultHTML += '<p style="color: red;"><strong>⚠️ Token已过期!</strong></p>';
|
||
} else {
|
||
const expireDate = new Date(payload.exp * 1000);
|
||
resultHTML += '<p style="color: green;"><strong>✅ Token有效,过期时间: ' + expireDate.toLocaleString() + '</strong></p>';
|
||
}
|
||
|
||
if (isValidJWT) {
|
||
resultHTML += '<p style="color: green;"><strong>✅ 这是有效的iMeeting JWT token!</strong></p>';
|
||
} else {
|
||
resultHTML += '<p style="color: red;"><strong>❌ 这不是有效的iMeeting JWT token</strong></p>';
|
||
}
|
||
|
||
resultHTML += '</div>';
|
||
resultDiv.innerHTML = resultHTML;
|
||
|
||
} catch (error) {
|
||
resultDiv.innerHTML = '<div class="result error">解码失败: ' + error.message + '</div>';
|
||
}
|
||
}
|
||
</script>
|
||
</body>
|
||
</html> |