fix(frontend): validate oidc state in callback flow
This commit is contained in:
@@ -32,8 +32,10 @@ const error = ref('')
|
|||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
try {
|
try {
|
||||||
const code = route.query.code
|
const code = route.query.code
|
||||||
|
const state = route.query.state
|
||||||
const oauthError = route.query.error
|
const oauthError = route.query.error
|
||||||
const oauthErrorDesc = route.query.error_description
|
const oauthErrorDesc = route.query.error_description
|
||||||
|
const expectedState = sessionStorage.getItem('oidc_expected_state')
|
||||||
|
|
||||||
if (oauthError) {
|
if (oauthError) {
|
||||||
const reason = typeof oauthErrorDesc === 'string' && oauthErrorDesc
|
const reason = typeof oauthErrorDesc === 'string' && oauthErrorDesc
|
||||||
@@ -50,6 +52,13 @@ onMounted(async () => {
|
|||||||
return
|
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 redirectUri = `${window.location.origin}/auth/callback`
|
||||||
const res = await exchangeOidcCode(code, redirectUri)
|
const res = await exchangeOidcCode(code, redirectUri)
|
||||||
const { access_token } = res.data
|
const { access_token } = res.data
|
||||||
@@ -65,10 +74,12 @@ onMounted(async () => {
|
|||||||
await authStore.fetchMe()
|
await authStore.fetchMe()
|
||||||
|
|
||||||
// 導向原頁面或預設的 /me
|
// 導向原頁面或預設的 /me
|
||||||
|
sessionStorage.removeItem('oidc_expected_state')
|
||||||
const redirect = sessionStorage.getItem('post_login_redirect') || '/me'
|
const redirect = sessionStorage.getItem('post_login_redirect') || '/me'
|
||||||
sessionStorage.removeItem('post_login_redirect')
|
sessionStorage.removeItem('post_login_redirect')
|
||||||
router.push(redirect)
|
router.push(redirect)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
sessionStorage.removeItem('oidc_expected_state')
|
||||||
const detail = err.response?.data?.detail
|
const detail = err.response?.data?.detail
|
||||||
if (detail === 'invalid_authorization_code') {
|
if (detail === 'invalid_authorization_code') {
|
||||||
error.value = '授權代碼無效,請重新登入'
|
error.value = '授權代碼無效,請重新登入'
|
||||||
|
|||||||
@@ -51,7 +51,13 @@ async function handleOidcLogin() {
|
|||||||
sessionStorage.setItem('post_login_redirect', typeof redirect === 'string' ? redirect : '/me')
|
sessionStorage.setItem('post_login_redirect', typeof redirect === 'string' ? redirect : '/me')
|
||||||
const callbackUrl = `${window.location.origin}/auth/callback`
|
const callbackUrl = `${window.location.origin}/auth/callback`
|
||||||
const res = await getOidcAuthorizeUrl(callbackUrl)
|
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) {
|
} catch (err) {
|
||||||
const detail = err.response?.data?.detail
|
const detail = err.response?.data?.detail
|
||||||
if (detail === 'authentik_login_not_configured') {
|
if (detail === 'authentik_login_not_configured') {
|
||||||
|
|||||||
Reference in New Issue
Block a user