fix(api): fix token handler

This commit is contained in:
2026-03-09 13:57:47 +08:00
parent 3b118e3304
commit e7670c7cef
4 changed files with 55 additions and 41 deletions

View File

@@ -17,6 +17,7 @@ fetch 参数:
"use client" "use client"
import { useUserStore } from "@/app/store/user" import { useUserStore } from "@/app/store/user"
import { usePermissionStore } from "@/components/label/store/auth"
import { deleteCookie, refreshKey } from "@/components/login/api" import { deleteCookie, refreshKey } from "@/components/login/api"
import { isNumber } from "@/libs/util" import { isNumber } from "@/libs/util"
@@ -40,6 +41,7 @@ interface OptionsProps {
async function httpfetch<T>(options: OptionsProps): Promise<T> { async function httpfetch<T>(options: OptionsProps): Promise<T> {
const { removeUserInfo, refreshToken } = useUserStore.getState() const { removeUserInfo, refreshToken } = useUserStore.getState()
const { logout } = usePermissionStore.getState()
const access_token = useUserStore.getState().access_token const access_token = useUserStore.getState().access_token
const refresh_token = useUserStore.getState().refresh_token const refresh_token = useUserStore.getState().refresh_token
@@ -186,24 +188,19 @@ async function httpfetch<T>(options: OptionsProps): Promise<T> {
return options.isDownload return options.isDownload
? retry_response.blob() ? retry_response.blob()
: retry_response.json() : retry_response.json()
} else {
const { code } = refreshResponse
if (code === 406) {
try {
await deleteCookie()
} catch (error) {
rejected(error)
} finally {
// 清空身份信息并跳转至登录页面
removeUserInfo()
window.location.href = "/login"
}
} else {
throw new Error("重新获取token失败")
}
} }
} catch (error) { } catch (error) {
rejected(error) rejected(error)
try {
await deleteCookie()
} catch (error) {
rejected(error)
} finally {
// 清空身份信息并跳转至登录页面
removeUserInfo()
logout()
window.location.href = "/login"
}
} }
} else if (status === 403) { } else if (status === 403) {
if ( if (
@@ -271,8 +268,7 @@ async function httpfetch<T>(options: OptionsProps): Promise<T> {
? retry_response.blob() ? retry_response.blob()
: retry_response.json() : retry_response.json()
} else { } else {
const { code } = refreshResponse if (refreshResponse.code === 406) {
if (code === 406) {
try { try {
await deleteCookie() await deleteCookie()
} catch (error) { } catch (error) {
@@ -280,6 +276,7 @@ async function httpfetch<T>(options: OptionsProps): Promise<T> {
} finally { } finally {
// 清空身份信息并跳转至登录页面 // 清空身份信息并跳转至登录页面
removeUserInfo() removeUserInfo()
logout()
window.location.href = "/login" window.location.href = "/login"
} }
} else { } else {

View File

@@ -46,32 +46,45 @@ export async function POST(req: any) {
} }
) )
} }
const userData = await genAccessToken(req) const userData = await genAccessToken(req)
const authorization = `bearer ${userData?.access_token}` let fetchOptions: any = {}
const fetchOptions: any = { if (isRefresh) {
method, if (!userData?.refresh_token) {
headers: { return NextResponse.json(
"content-type": "application/json", { message: "Refresh token is empty", code: 406 },
authorization: authorization, { status: 200 }
}, )
} }
fetchOptions = {
if (method === "POST" || method === "PUT") { method,
let refreshBody = JSON.stringify({ headers: {
...JSON.parse(data), "content-type": "application/json",
token: userData?.refresh_token || "", },
}) body: JSON.stringify({
fetchOptions.body = isRefresh ? refreshBody : data token: userData?.refresh_token,
}),
}
} else { } else {
if (isParamsValid(data)) { const authorization = `bearer ${userData?.access_token}`
let test = "" fetchOptions = {
for (const [key, value] of Object.entries(data)) { method,
test += `&${key}=${value}` headers: {
"content-type": "application/json",
authorization: authorization,
},
}
if (method === "POST" || method === "PUT") {
fetchOptions.body = data
} else {
if (isParamsValid(data)) {
let test = ""
for (const [key, value] of Object.entries(data)) {
test += `&${key}=${value}`
}
url += `?${test}`
} }
url += `?${test}`
} }
} }

View File

@@ -32,6 +32,7 @@ import headerLinkClasses from "./HeaderLink.module.css"
import { useUserStore } from "@/app/store/user" import { useUserStore } from "@/app/store/user"
import { usePathname, useRouter } from "next/navigation" import { usePathname, useRouter } from "next/navigation"
import { usePermissionStore } from "../label/store/auth"
import { deleteCookie } from "../login/api" import { deleteCookie } from "../login/api"
import { MenuItem, withoutLayoutRoutes } from "./common" import { MenuItem, withoutLayoutRoutes } from "./common"
import { ClientIcon } from "./components/ClientIcon" import { ClientIcon } from "./components/ClientIcon"
@@ -140,6 +141,7 @@ export default function AppLayout({
const handleLogout = async () => { const handleLogout = async () => {
useUserStore.getState().removeUserInfo() useUserStore.getState().removeUserInfo()
usePermissionStore.getState().logout()
process.env.NEXT_PUBLIC_OUTPUT_TYPE === "standalone" && process.env.NEXT_PUBLIC_OUTPUT_TYPE === "standalone" &&
(await deleteCookie()) (await deleteCookie())
router.push("/login") router.push("/login")

View File

@@ -1,8 +1,8 @@
import { ResultData } from "@/api/typing" import { ResultData } from "@/api/typing"
import { Login } from "@/components/login/api/types"
import redis from "@/components/login/libs/redis" import redis from "@/components/login/libs/redis"
import { encrypt, generateKeyFromEnv } from "@/components/login/libs/session" import { encrypt, generateKeyFromEnv } from "@/components/login/libs/session"
import { cookies } from "next/headers" import { cookies } from "next/headers"
import { Login } from "@/components/login/api/types"
export const handleLoginData = async (props: { export const handleLoginData = async (props: {
clientIP: string clientIP: string
@@ -75,8 +75,10 @@ export const handleRefreshToken = async (props: {
...data, ...data,
message: { message: {
...data.message, ...data.message,
access_token: "", // access_token: "",
refresh_token: "", // refresh_token: "",
access: "",
refresh: "",
}, },
} }
} }