oidc-gateway-demo/resourceservicehtml/callback.html

204 lines
6.9 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>OIDC回调处理</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 600px;
margin: 50px auto;
padding: 20px;
background-color: #f5f5f5;
}
.container {
background: white;
padding: 30px;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
text-align: center;
}
.status {
padding: 15px;
margin: 10px 0;
border-radius: 5px;
}
.success { background-color: #d4edda; color: #155724; border: 1px solid #c3e6cb; }
.error { background-color: #f8d7da; color: #721c24; border: 1px solid #f5c6cb; }
.loading { background-color: #d1ecf1; color: #0c5460; border: 1px solid #bee5eb; }
.spinner {
border: 4px solid #f3f3f3;
border-top: 4px solid #3498db;
border-radius: 50%;
width: 40px;
height: 40px;
animation: spin 1s linear infinite;
margin: 20px auto;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
</style>
</head>
<body>
<div class="container">
<h1>处理OIDC回调</h1>
<div id="status" class="status loading">
<div class="spinner"></div>
<p>正在处理认证回调...</p>
</div>
<div id="result" style="display: none;">
<div id="resultContent"></div>
<button onclick="goToMain()" style="margin-top: 20px; padding: 10px 20px; background-color: #007bff; color: white; border: none; border-radius: 5px; cursor: pointer;">
返回主页
</button>
</div>
</div>
<script>
// OIDC配置
const oidcConfig = {
clientId: 'a-client',
clientSecret: 'a-secret',
redirectUri: 'https://a.local.com/callback',
tokenEndpoint: 'https://oidc.local.com/oauth2/token',
userInfoEndpoint: 'https://oidc.local.com/userinfo'
};
// 页面加载时执行
window.onload = function() {
const urlParams = new URLSearchParams(window.location.search);
const code = urlParams.get('code');
const state = urlParams.get('state');
const error = urlParams.get('error');
if (error) {
showError('认证失败: ' + error);
return;
}
if (!code) {
showError('未收到授权码');
return;
}
// 验证state参数
const savedState = localStorage.getItem('oauth_state');
if (state !== savedState) {
showError('状态验证失败可能存在CSRF攻击');
return;
}
// 交换授权码为token
exchangeCodeForToken(code);
};
// 交换授权码为token
function exchangeCodeForToken(code) {
const tokenData = new URLSearchParams();
tokenData.append('grant_type', 'authorization_code');
tokenData.append('code', code);
tokenData.append('redirect_uri', oidcConfig.redirectUri);
// 使用Basic认证
const credentials = btoa(oidcConfig.clientId + ':' + oidcConfig.clientSecret);
fetch(oidcConfig.tokenEndpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Basic ' + credentials
},
body: tokenData
})
.then(response => {
if (!response.ok) {
return response.json().then(err => {
throw new Error(`Token交换失败: ${err.error || response.statusText}`);
});
}
return response.json();
})
.then(data => {
if (data.access_token) {
// 保存token
localStorage.setItem('access_token', data.access_token);
if (data.refresh_token) {
localStorage.setItem('refresh_token', data.refresh_token);
}
// 清除state
localStorage.removeItem('oauth_state');
showSuccess('认证成功!正在获取用户信息...');
// 获取用户信息
return fetch(oidcConfig.userInfoEndpoint, {
headers: {
'Authorization': `Bearer ${data.access_token}`
}
});
} else {
throw new Error('响应中未包含access_token');
}
})
.then(response => {
if (!response.ok) {
throw new Error('获取用户信息失败');
}
return response.json();
})
.then(userInfo => {
showSuccess(`认证成功!欢迎 ${userInfo.sub || 'user'}`);
})
.catch(error => {
console.error('认证过程出错:', error);
showError('认证失败: ' + error.message);
});
}
// 显示成功信息
function showSuccess(message) {
document.getElementById('status').className = 'status success';
document.getElementById('status').innerHTML = `
<h3>✅ 成功</h3>
<p>${message}</p>
`;
setTimeout(() => {
document.getElementById('result').style.display = 'block';
document.getElementById('resultContent').innerHTML = `
<h3>认证完成</h3>
<p>您已成功登录系统A</p>
<p>Token已保存到本地存储</p>
`;
}, 1000);
}
// 显示错误信息
function showError(message) {
document.getElementById('status').className = 'status error';
document.getElementById('status').innerHTML = `
<h3>❌ 错误</h3>
<p>${message}</p>
`;
setTimeout(() => {
document.getElementById('result').style.display = 'block';
document.getElementById('resultContent').innerHTML = `
<h3>认证失败</h3>
<p>请检查错误信息并重试</p>
`;
}, 1000);
}
// 返回主页
function goToMain() {
window.location.href = '/';
}
</script>
</body>
</html>