refactor(web): migrate OAuth redirect storage to utility and preserve query params

- Use storage utility instead of raw localStorage for OAuth pending
  redirect with legacy fallback for backward compatibility
- Forward search params from root page to /apps so query strings
  (e.g. redirect_url) are not lost during server-side redirect
This commit is contained in:
yyh 2026-02-10 14:23:47 +08:00
parent b906188cf9
commit 868423a138
No known key found for this signature in database
3 changed files with 56 additions and 14 deletions

View File

@ -19,6 +19,7 @@ import { useLanguage } from '@/app/components/header/account-setting/model-provi
import { useAppContext } from '@/context/app-context'
import { useIsLogin } from '@/service/use-common'
import { useAuthorizeOAuthApp, useOAuthAppInfo } from '@/service/use-oauth'
import { storage } from '@/utils/storage'
import {
OAUTH_AUTHORIZE_PENDING_KEY,
OAUTH_AUTHORIZE_PENDING_TTL,
@ -30,7 +31,7 @@ function setItemWithExpiry(key: string, value: string, ttl: number) {
value,
expiry: Math.floor((Date.now() + ttl * 1000) / 1000),
}
localStorage.setItem(key, JSON.stringify(item))
storage.set(key, item)
}
function buildReturnUrl(pathname: string, search: string) {

View File

@ -1,5 +1,27 @@
import { redirect } from 'next/navigation'
const Home = () => redirect('/apps')
type HomePageProps = {
searchParams: Promise<Record<string, string | string[] | undefined>>
}
const Home = async ({ searchParams }: HomePageProps) => {
const resolvedSearchParams = await searchParams
const urlSearchParams = new URLSearchParams()
Object.entries(resolvedSearchParams).forEach(([key, value]) => {
if (value === undefined)
return
if (Array.isArray(value)) {
value.forEach(item => urlSearchParams.append(key, item))
return
}
urlSearchParams.set(key, value)
})
const queryString = urlSearchParams.toString()
redirect(queryString ? `/apps?${queryString}` : '/apps')
}
export default Home

View File

@ -1,31 +1,50 @@
import type { ReadonlyURLSearchParams } from 'next/navigation'
import { OAUTH_AUTHORIZE_PENDING_KEY, REDIRECT_URL_KEY } from '@/app/account/oauth/authorize/constants'
import { storage } from '@/utils/storage'
const getCurrentUnixTimestamp = () => Math.floor(Date.now() / 1000)
type OAuthPendingRedirect = {
value?: string
expiry?: number
}
function getOAuthPendingRedirect(): string | null {
const itemStr = localStorage.getItem(OAUTH_AUTHORIZE_PENDING_KEY)
if (!itemStr)
return null
function getLegacyOAuthPendingRedirect(): OAuthPendingRedirect | null {
try {
const item = JSON.parse(itemStr)
localStorage.removeItem(OAUTH_AUTHORIZE_PENDING_KEY)
if (!item?.value)
return null
return getCurrentUnixTimestamp() > item.expiry ? null : item.value
const itemStr = localStorage.getItem(OAUTH_AUTHORIZE_PENDING_KEY)
return itemStr ? JSON.parse(itemStr) : null
}
catch {
return null
}
}
function removeOAuthPendingRedirect() {
storage.remove(OAUTH_AUTHORIZE_PENDING_KEY)
try {
localStorage.removeItem(OAUTH_AUTHORIZE_PENDING_KEY)
}
catch {
// ignore legacy key cleanup failures
}
}
function getOAuthPendingRedirect(): string | null {
const item = storage.get<OAuthPendingRedirect>(OAUTH_AUTHORIZE_PENDING_KEY) ?? getLegacyOAuthPendingRedirect()
if (!item)
return null
removeOAuthPendingRedirect()
if (!item.value || typeof item.expiry !== 'number')
return null
return getCurrentUnixTimestamp() > item.expiry ? null : item.value
}
export const resolvePostLoginRedirect = (searchParams: ReadonlyURLSearchParams) => {
const redirectUrl = searchParams.get(REDIRECT_URL_KEY)
if (redirectUrl) {
try {
localStorage.removeItem(OAUTH_AUTHORIZE_PENDING_KEY)
removeOAuthPendingRedirect()
return decodeURIComponent(redirectUrl)
}
catch (e) {