Add SSO and device management samples
This commit is contained in:
316
test-login-sdk.html
Normal file
316
test-login-sdk.html
Normal file
@@ -0,0 +1,316 @@
|
||||
<!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>
|
||||
Reference in New Issue
Block a user