From 153a3744695673d1179e80cb5730fb7765463524 Mon Sep 17 00:00:00 2001 From: feige996 <1020102647@qq.com> Date: Fri, 22 Aug 2025 16:16:17 +0800 Subject: [PATCH] =?UTF-8?q?refactor(auth):=20=E9=87=8D=E6=9E=84=E8=AE=A4?= =?UTF-8?q?=E8=AF=81=E6=A8=A1=E5=9D=97=E4=BB=A5=E6=94=AF=E6=8C=81=E5=8F=8C?= =?UTF-8?q?token=E6=A8=A1=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 将用户认证逻辑从user store迁移到token store 新增双token模式支持及相关类型定义 更新路由拦截器和http模块以适配新的认证结构 --- src/api/login.ts | 16 ++---- src/api/types/login.ts | 48 +++++++++++----- src/http/http.ts | 13 +++-- src/pages/me/me.vue | 8 ++- src/router/interceptor.ts | 8 +-- src/store/token.ts | 112 ++++++++++++++++++++++++++++++++++++++ src/store/user.ts | 95 ++++---------------------------- src/utils/index.ts | 5 ++ 8 files changed, 184 insertions(+), 121 deletions(-) create mode 100644 src/store/token.ts diff --git a/src/api/login.ts b/src/api/login.ts index fcc72af..a8498e7 100644 --- a/src/api/login.ts +++ b/src/api/login.ts @@ -1,4 +1,4 @@ -import type { ICaptcha, IUpdateInfo, IUpdatePassword, IUserInfoVo, IUserLogin } from './types/login' +import type { IAuthLoginRes, ICaptcha, IDoubleTokenRes, IUpdateInfo, IUpdatePassword, IUserInfoRes } from './types/login' import { http } from '@/http/http' /** @@ -24,7 +24,7 @@ export function getCode() { * @param loginForm 登录表单 */ export function login(loginForm: ILoginForm) { - return http.post('/user/login', loginForm) + return http.post('/auth/login', loginForm) } /** @@ -32,21 +32,21 @@ export function login(loginForm: ILoginForm) { * @param refreshToken 刷新token */ export function refreshToken(refreshToken: string) { - return http.post('/user/refreshToken', { refreshToken }) + return http.post('/auth/refreshToken', { refreshToken }) } /** * 获取用户信息 */ export function getUserInfo() { - return http.get('/user/info') + return http.get('/user/info') } /** * 退出登录 */ export function logout() { - return http.get('/user/logout') + return http.get('/auth/logout') } /** @@ -77,15 +77,11 @@ export function getWxCode() { }) } -/** - * 微信登录参数 - */ - /** * 微信登录 * @param params 微信登录参数,包含code * @returns Promise 包含登录结果 */ export function wxLogin(data: { code: string }) { - return http.post('/user/wxLogin', data) + return http.post('/auth/wxLogin', data) } diff --git a/src/api/types/login.ts b/src/api/types/login.ts index 455ae19..5b1af02 100644 --- a/src/api/types/login.ts +++ b/src/api/types/login.ts @@ -1,24 +1,42 @@ -/** - * 用户信息 - */ -export interface IUserInfoVo { - id: number | string - username: string - avatar: string +// 认证模式类型 +export type AuthMode = 'single' | 'double' + +// 单Token响应类型 +export interface ISingleTokenRes { token: string - refreshToken?: string - refreshExpire?: number + expiresIn: number // 有效期(秒) +} + +// 双Token响应类型 +export interface IDoubleTokenRes { + accessToken: string + refreshToken: string + accessExpiresIn: number // 访问令牌有效期(秒) + refreshExpiresIn: number // 刷新令牌有效期(秒) } /** - * 登录返回的信息 + * 登录返回的信息,其实就是 token 信息 */ -export interface IUserLogin { - id: string +export type IAuthLoginRes = ISingleTokenRes | IDoubleTokenRes + +/** + * 用户信息 + */ +export interface IUserInfoRes { + userId: number username: string - token: string - refreshToken?: string - refreshExpire?: number + nickname: string + avatar?: string + [key: string]: any // 允许其他扩展字段 +} + +// 认证存储数据结构 +export interface AuthStorage { + mode: AuthMode + tokens: ISingleTokenRes | IDoubleTokenRes + userInfo?: IUserInfoRes + loginTime: number // 登录时间戳 } /** diff --git a/src/http/http.ts b/src/http/http.ts index 864518d..507c25a 100644 --- a/src/http/http.ts +++ b/src/http/http.ts @@ -1,6 +1,7 @@ +import type { IDoubleTokenRes } from '@/api/types/login' import type { CustomRequestOptions } from '@/http/types' import { nextTick } from 'vue' -import { useUserStore } from '@/store/user' +import { useTokenStore } from '@/store/token' // 刷新 token 状态管理 let refreshing = false // 防止重复刷新 token 标识 @@ -27,15 +28,15 @@ export function http(options: CustomRequestOptions) { } const resData: IResData = res.data as IResData if ((res.statusCode === 401) || (resData.code === 401)) { - const store = useUserStore() + const tokenStore = useTokenStore() if (sessionMode === 'single') { // 未启用双token策略,清理用户信息,跳转到登录页 - store.logout() + tokenStore.logout() uni.navigateTo({ url: '/pages/login/login' }) return reject(res) } /* -------- 无感刷新 token ----------- */ - const { refreshToken } = store.userInfo || {} + const { refreshToken } = tokenStore.tokenInfo as IDoubleTokenRes || {} // token 失效的,且有刷新 token 的,才放到请求队列里 if ((res.statusCode === 401 || resData.code === 401) && refreshToken) { taskQueue.push(() => { @@ -47,7 +48,7 @@ export function http(options: CustomRequestOptions) { refreshing = true try { // 发起刷新 token 请求(使用 store 的 refreshToken 方法) - await store.refreshToken() + await tokenStore.refreshToken() // 刷新 token 成功 refreshing = false nextTick(() => { @@ -74,7 +75,7 @@ export function http(options: CustomRequestOptions) { }) }) // 清除用户信息 - await store.logout() + await tokenStore.logout() // 跳转到登录页 setTimeout(() => { uni.navigateTo({ url: '/pages/login/login' }) diff --git a/src/pages/me/me.vue b/src/pages/me/me.vue index 0e6e8b5..d926110 100644 --- a/src/pages/me/me.vue +++ b/src/pages/me/me.vue @@ -13,9 +13,11 @@ import type { IUploadSuccessInfo } from '@/api/types/login' import { storeToRefs } from 'pinia' import { useUserStore } from '@/store' +import { useTokenStore } from '@/store/token' import { useUpload } from '@/utils/uploadFile' const userStore = useUserStore() +const tokenStore = useTokenStore() // 使用storeToRefs解构userInfo const { userInfo } = storeToRefs(userStore) @@ -38,7 +40,7 @@ async function handleLogin() { // #ifdef MP-WEIXIN // 微信登录 - await userStore.wxLogin() + await tokenStore.wxLogin() // #endif // #ifndef MP-WEIXIN uni.navigateTo({ url: '/pages/login/login' }) @@ -80,7 +82,7 @@ function handleLogout() { success: (res) => { if (res.confirm) { // 清空用户信息 - useUserStore().logout() + useTokenStore().logout() // 执行退出登录逻辑 uni.showToast({ title: '退出登录成功', @@ -140,7 +142,7 @@ function handleLogout() { -