- LoginView 挂载时等待 OIDC 配置就绪后显式调用自动触发逻辑 - 新增 oidcAutoStart.js 工具模块,支持 autostartOidc 参数判断和 sessionStorage 防循环 - OIDC 回调成功后清理自动触发标记,避免影响下一次跨系统登录 - 已登录用户访问 /login 时按 redirect 参数跳转目标页,不再固定跳回首页 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
78 lines
2.2 KiB
JavaScript
78 lines
2.2 KiB
JavaScript
const AUTO_START_KEY = 'oidc_auto_start_attempted'
|
||
|
||
// 对 redirect 参数进行安全校验,防止开放重定向漏洞
|
||
// - 必须是字符串类型
|
||
// - 必须以 / 开头(本地相对路径)
|
||
// - 不能以 // 或 \ 开头(协议相对 URL / 非标准路径)
|
||
// 不合法或缺失时返回 "/"
|
||
export function sanitizeRedirect(value) {
|
||
if (typeof value === 'string' && value.length > 0 && value[0] === '/' && value[1] !== '/' && value[1] !== '\\') {
|
||
return value
|
||
}
|
||
return '/'
|
||
}
|
||
|
||
// 检查是否已经尝试过自动触发 OIDC(同一会话内,避免无限循环)
|
||
export function hasAutoStartAttempted() {
|
||
return sessionStorage.getItem(AUTO_START_KEY) === '1'
|
||
}
|
||
|
||
// 标记已尝试自动触发
|
||
export function markAutoStartAttempted() {
|
||
sessionStorage.setItem(AUTO_START_KEY, '1')
|
||
}
|
||
|
||
// 清除自动触发尝试标记(OIDC 登录成功后调用)
|
||
export function clearAutoStartAttempt() {
|
||
sessionStorage.removeItem(AUTO_START_KEY)
|
||
}
|
||
|
||
// 尝试自动触发 OIDC 登录
|
||
// config: OIDC 配置对象(由调用方在外部获取)
|
||
// getOIDCLoginUrl: 获取登录 URL 的异步函数
|
||
// 返回 true 表示已发起跳转,caller 不应继续执行后续流程
|
||
export async function tryAutoStartOIDC(getOIDCLoginUrl, config) {
|
||
// 1. OIDC 配置未就绪或未启用
|
||
if (!config || !config.enabled) {
|
||
return false
|
||
}
|
||
|
||
// 2. 有 oidc_error 时不再自动触发,避免循环
|
||
const params = new URLSearchParams(window.location.search)
|
||
if (params.has('oidc_error')) {
|
||
return false
|
||
}
|
||
|
||
// 3. 必须有 autostartOidc 参数
|
||
if (!params.has('autostartOidc')) {
|
||
return false
|
||
}
|
||
|
||
// 4. 同一会话内已尝试过,不再重复
|
||
if (hasAutoStartAttempted()) {
|
||
return false
|
||
}
|
||
|
||
// 5. 获取 OIDC 登录 URL 并跳转
|
||
let loginUrlResp
|
||
try {
|
||
loginUrlResp = await getOIDCLoginUrl()
|
||
} catch {
|
||
return false
|
||
}
|
||
|
||
if (!loginUrlResp || !loginUrlResp.login_url) {
|
||
return false
|
||
}
|
||
|
||
// 保存当前路径,登录后返回(安全校验)
|
||
const redirectPath = sanitizeRedirect(params.get('redirect'))
|
||
sessionStorage.setItem('oidc_redirect', redirectPath)
|
||
|
||
// 标记已尝试,防止下次再自动触发
|
||
markAutoStartAttempted()
|
||
|
||
window.location.href = loginUrlResp.login_url
|
||
return true
|
||
}
|