317 lines
12 KiB
HTML
317 lines
12 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN" class="light-style customizer-hide">
|
||
<head>
|
||
<meta charset="utf-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||
<title>Fido2 Login SDK Test</title>
|
||
<link rel="stylesheet" href="files/core.css" />
|
||
<link rel="stylesheet" href="files/theme-default.css" />
|
||
<link rel="stylesheet" href="files/fido2-ui-sdk.css" />
|
||
<style>
|
||
.status-indicator {
|
||
display: inline-block;
|
||
width: 10px;
|
||
height: 10px;
|
||
border-radius: 50%;
|
||
margin-right: 5px;
|
||
}
|
||
.status-registered { background-color: #28a745; }
|
||
.status-unregistered { background-color: #dc3545; }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="container py-5">
|
||
<div class="row justify-content-center">
|
||
<div class="col-md-10">
|
||
<div class="card">
|
||
<div class="card-header d-flex justify-content-between align-items-center">
|
||
<h4 class="mb-0">Fido2 Login SDK 测试</h4>
|
||
<div>
|
||
<span class="status-indicator" id="regStatusIndicator"></span>
|
||
<small class="text-muted" id="regStatusText">检查中...</small>
|
||
</div>
|
||
</div>
|
||
<div class="card-body">
|
||
<div class="row mb-4">
|
||
<div class="col-md-6">
|
||
<div class="card bg-light">
|
||
<div class="card-body">
|
||
<h5>设备注册测试</h5>
|
||
<div class="mb-2">
|
||
<input type="text" class="form-control" id="testUserId" placeholder="输入User ID" value="testuser">
|
||
</div>
|
||
<div class="mb-2">
|
||
<input type="text" class="form-control" id="testDisplayName" placeholder="显示名称" value="测试设备">
|
||
</div>
|
||
<div class="alert alert-info py-1 px-2 mb-2" style="font-size: 12px;">
|
||
<small>💡 <strong>提示:</strong>使用新User ID注册可测试自动登录流程</small>
|
||
</div>
|
||
<button class="btn btn-success btn-sm me-2" id="registerDeviceBtn">
|
||
注册Passkey设备
|
||
</button>
|
||
<button class="btn btn-outline-primary btn-sm" id="checkRegBtn">
|
||
检查状态
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="col-md-6">
|
||
<div class="card bg-light">
|
||
<div class="card-body">
|
||
<h5>登录组件测试</h5>
|
||
<button class="btn btn-primary me-2" id="testLoginBtn">
|
||
启动登录组件
|
||
</button>
|
||
<button class="btn btn-secondary me-2" id="testDestroyBtn">
|
||
销毁组件
|
||
</button>
|
||
<button class="btn btn-outline-info btn-sm" id="checkStateBtn">
|
||
检查状态
|
||
</button>
|
||
<div class="mt-2">
|
||
<small class="text-muted" id="loginStateText">未启动</small>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<hr />
|
||
|
||
<h5>测试日志:</h5>
|
||
<div id="testLog" class="bg-light p-3" style="max-height: 300px; overflow-y: auto; font-family: monospace; font-size: 12px;">
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="login-container"></div>
|
||
|
||
<script src="files/popper.js"></script>
|
||
<script src="files/bootstrap.js"></script>
|
||
<script src="files/dfido2-lib.js"></script>
|
||
<script src="files/fido2-ui-sdk.js"></script>
|
||
|
||
<script>
|
||
// 清理旧会话(只清理会话,不影响注册状态)
|
||
logoutFido2UserSession();
|
||
console.log('已清理旧会话');
|
||
console.log('dfido2_lib_registered:', localStorage.getItem('dfido2_lib_registered'));
|
||
|
||
// 通过配置传递服务器URL,不直接操作localStorage
|
||
window.serverUrl = 'https://local.dqj-macpro.com';
|
||
|
||
// 设置调试日志函数
|
||
window.fido2LoginDebug = function(message) {
|
||
log(`[SDK] ${message}`, 'info');
|
||
};
|
||
|
||
function log(message, type = 'info') {
|
||
const logEl = document.getElementById('testLog');
|
||
const time = new Date().toLocaleTimeString();
|
||
const color = type === 'error' ? 'red' : type === 'success' ? 'green' : type === 'warn' ? 'orange' : type === 'debug' ? 'purple' : 'blue';
|
||
logEl.innerHTML += `<div style="color: ${color};">[${time}] ${message}</div>`;
|
||
logEl.scrollTop = logEl.scrollHeight;
|
||
console.log(`[${type.toUpperCase()}]`, message);
|
||
}
|
||
|
||
// 设置调试日志函数
|
||
window.fido2LoginDebug = function(message) {
|
||
log(`[SDK] ${message}`, 'info');
|
||
};
|
||
|
||
function log(message, type = 'info') {
|
||
const logEl = document.getElementById('testLog');
|
||
const time = new Date().toLocaleTimeString();
|
||
const color = type === 'error' ? 'red' : type === 'success' ? 'green' : type === 'warn' ? 'orange' : type === 'debug' ? 'purple' : 'blue';
|
||
logEl.innerHTML += `<div style="color: ${color};">[${time}] ${message}</div>`;
|
||
logEl.scrollTop = logEl.scrollHeight;
|
||
console.log(`[${type.toUpperCase()}]`, message);
|
||
}
|
||
|
||
function updateRegStatus() {
|
||
const registered = localStorage.getItem('dfido2_lib_registered');
|
||
const indicator = document.getElementById('regStatusIndicator');
|
||
const text = document.getElementById('regStatusText');
|
||
|
||
if (registered) {
|
||
indicator.className = 'status-indicator status-registered';
|
||
text.textContent = '已注册设备';
|
||
} else {
|
||
indicator.className = 'status-indicator status-unregistered';
|
||
text.textContent = '未注册设备';
|
||
}
|
||
}
|
||
|
||
function updateLoginState(state) {
|
||
document.getElementById('loginStateText').textContent = state || '未启动';
|
||
}
|
||
|
||
let loginManager = null;
|
||
|
||
// 页面加载时检查状态
|
||
updateRegStatus();
|
||
log('测试页面已加载完成');
|
||
log('💡 使用新User ID注册设备,然后启动登录组件测试自动Fido2登录');
|
||
|
||
// 注册设备
|
||
document.getElementById('registerDeviceBtn').addEventListener('click', async function() {
|
||
const userId = document.getElementById('testUserId').value.trim();
|
||
const displayName = document.getElementById('testDisplayName').value.trim() || 'Device-' + userId;
|
||
|
||
if (!userId) {
|
||
log('请输入User ID', 'error');
|
||
return;
|
||
}
|
||
|
||
log(`正在为用户 ${userId} 注册设备...`);
|
||
log(`服务器URL: ${window.serverUrl}`);
|
||
|
||
try {
|
||
const result = await registerFido2(userId, displayName, null);
|
||
if (result.status === 'ok') {
|
||
log(`✅ 设备注册成功!`, 'success');
|
||
log(`dfido2_lib_registered: ${localStorage.getItem('dfido2_lib_registered')}`);
|
||
updateRegStatus();
|
||
} else {
|
||
log(`❌ 设备注册失败: ${result.errorMessage}`, 'error');
|
||
}
|
||
} catch (error) {
|
||
log(`❌ 注册异常: ${error.message}`, 'error');
|
||
}
|
||
});
|
||
|
||
// 检查注册状态
|
||
document.getElementById('checkRegBtn').addEventListener('click', function() {
|
||
const registered = localStorage.getItem('dfido2_lib_registered');
|
||
const session = sessionStorage.getItem('fido2_user_session');
|
||
log(`dfido2_lib_registered: ${registered || 'null'}`);
|
||
log(`fido2_user_session: ${session ? '存在' : 'null'}`);
|
||
log(`canTryAutoAuthentication(): ${canTryAutoAuthentication()}`);
|
||
updateRegStatus();
|
||
});
|
||
|
||
// 检查登录状态
|
||
document.getElementById('checkStateBtn').addEventListener('click', function() {
|
||
if (loginManager) {
|
||
log(`登录组件状态: ${loginManager.getState()}`);
|
||
log(`登录模式: ${loginManager.getMode()}`);
|
||
log(`尝试次数: ${loginManager.getAttemptCount()}/${loginManager.maxAttempts}`);
|
||
updateLoginState(loginManager.getState() + ' - ' + loginManager.getMode());
|
||
} else {
|
||
log('登录组件未启动');
|
||
updateLoginState('未启动');
|
||
}
|
||
});
|
||
|
||
// 启动登录组件
|
||
document.getElementById('testLoginBtn').addEventListener('click', function() {
|
||
// 确保调试函数已设置
|
||
window.fido2LoginDebug = function(message) {
|
||
log(`[SDK] ${message}`, 'info');
|
||
};
|
||
|
||
log('========================================');
|
||
log('启动登录组件...');
|
||
log(`canTryAutoAuthentication() = ${canTryAutoAuthentication()}`);
|
||
log(`dfido2_lib_registered = ${localStorage.getItem('dfido2_lib_registered')}`);
|
||
log('========================================');
|
||
|
||
if (loginManager) {
|
||
log('已有登录组件实例,先销毁');
|
||
loginManager.destroy();
|
||
loginManager = null;
|
||
}
|
||
|
||
try {
|
||
// 清理旧的modal元素和容器内容
|
||
const container = document.querySelector('#login-container');
|
||
if (container) {
|
||
container.innerHTML = '';
|
||
}
|
||
const oldModal = document.querySelector('.fido2-sdk-login-modal');
|
||
if (oldModal) {
|
||
oldModal.remove();
|
||
log('清理旧modal元素');
|
||
}
|
||
|
||
// 短暂延迟确保DOM清理完成
|
||
setTimeout(function() {
|
||
loginManager = Fido2UIManager.renderLogin({
|
||
serverUrl: window.serverUrl, // 通过SDK配置传递服务器URL
|
||
container: '#login-container',
|
||
features: {
|
||
autoAuth: true,
|
||
enablePasswordLogin: true,
|
||
autoShowPassword: false,
|
||
maxPasswordAttempts: 3,
|
||
showRemainingAttempts: true
|
||
},
|
||
callbacks: {
|
||
onFido2Success: function(userId, session) {
|
||
log(`✅✅✅ Fido2登录成功: ${userId}`, 'success');
|
||
log(`Session: ${session ? '存在' : 'null'}`);
|
||
updateLoginState('登录成功');
|
||
},
|
||
onFido2Error: function(error) {
|
||
log(`❌ Fido2失败: [${error.code}] ${error.message}`, 'error');
|
||
updateLoginState('Fido2失败: ' + error.code);
|
||
if (error.originalError) {
|
||
log(`原始错误: ${JSON.stringify(error.originalError).substring(0, 300)}`);
|
||
}
|
||
},
|
||
onPasswordLogin: function(userId, password) {
|
||
log(`🔐 密码登录尝试: userId="${userId}", password="***${password.slice(-2)}"`);
|
||
// 模拟密码验证
|
||
return new Promise(function(resolve) {
|
||
setTimeout(function() {
|
||
// This is demo code, accept any password
|
||
log('✅ 密码验证成功', 'success');
|
||
updateLoginState('密码登录成功');
|
||
resolve(true);
|
||
}, 500);
|
||
});
|
||
},
|
||
onPasswordExhausted: function(userId, attempts, maxAttempts) {
|
||
log(`🚫 密码重试次数耗尽: ${userId} (${attempts}/${maxAttempts})`, 'error');
|
||
updateLoginState('密码次数耗尽');
|
||
},
|
||
onLoginClosed: function() {
|
||
log('🔒 登录UI已关闭');
|
||
updateLoginState('已关闭');
|
||
}
|
||
},
|
||
theme: {
|
||
primaryColor: '#ce59d6',
|
||
backgroundColor: '#ffffff',
|
||
borderRadius: '8px'
|
||
},
|
||
language: 'zh-CN'
|
||
});
|
||
|
||
log('✅ 登录组件已启动');
|
||
}, 100);
|
||
} catch (error) {
|
||
log(`❌ 启动失败: ${error.message}`, 'error');
|
||
console.error(error);
|
||
}
|
||
});
|
||
|
||
// 销毁组件
|
||
document.getElementById('testDestroyBtn').addEventListener('click', function() {
|
||
if (loginManager) {
|
||
log('销毁登录组件...');
|
||
loginManager.destroy();
|
||
loginManager = null;
|
||
updateLoginState('已销毁');
|
||
log('✅ 组件已销毁');
|
||
} else {
|
||
log('没有活动的登录组件');
|
||
}
|
||
});
|
||
</script>
|
||
</body>
|
||
</html>
|