fix(frontend): validate oidc state in callback flow

This commit is contained in:
Chris
2026-03-30 02:47:16 +08:00
parent 7b3f5bd5b8
commit e325642b5e
2 changed files with 18 additions and 1 deletions

View File

@@ -32,8 +32,10 @@ const error = ref('')
onMounted(async () => {
try {
const code = route.query.code
const state = route.query.state
const oauthError = route.query.error
const oauthErrorDesc = route.query.error_description
const expectedState = sessionStorage.getItem('oidc_expected_state')
if (oauthError) {
const reason = typeof oauthErrorDesc === 'string' && oauthErrorDesc
@@ -50,6 +52,13 @@ onMounted(async () => {
return
}
if (!state || !expectedState || state !== expectedState) {
sessionStorage.removeItem('oidc_expected_state')
error.value = '登入驗證失敗,請重新登入'
setTimeout(() => router.push('/login'), 3000)
return
}
const redirectUri = `${window.location.origin}/auth/callback`
const res = await exchangeOidcCode(code, redirectUri)
const { access_token } = res.data
@@ -65,10 +74,12 @@ onMounted(async () => {
await authStore.fetchMe()
// 導向原頁面或預設的 /me
sessionStorage.removeItem('oidc_expected_state')
const redirect = sessionStorage.getItem('post_login_redirect') || '/me'
sessionStorage.removeItem('post_login_redirect')
router.push(redirect)
} catch (err) {
sessionStorage.removeItem('oidc_expected_state')
const detail = err.response?.data?.detail
if (detail === 'invalid_authorization_code') {
error.value = '授權代碼無效,請重新登入'

View File

@@ -51,7 +51,13 @@ async function handleOidcLogin() {
sessionStorage.setItem('post_login_redirect', typeof redirect === 'string' ? redirect : '/me')
const callbackUrl = `${window.location.origin}/auth/callback`
const res = await getOidcAuthorizeUrl(callbackUrl)
window.location.href = res.data.authorize_url
const authorizeUrl = res.data.authorize_url
const parsed = new URL(authorizeUrl)
const state = parsed.searchParams.get('state')
if (state) {
sessionStorage.setItem('oidc_expected_state', state)
}
window.location.href = authorizeUrl
} catch (err) {
const detail = err.response?.data?.detail
if (detail === 'authentik_login_not_configured') {