refactor(auth): 重构用户信息存储逻辑,添加缓存和工具函数
将直接操作 localStorage 的用户信息逻辑封装到工具函数中 添加缓存机制减少 localStorage 读取次数 提供统一的用户信息获取、设置和删除方法
Showing
3 changed files
with
105 additions
and
10 deletions
| ... | @@ -11,6 +11,7 @@ import { ref, provide, inject, onMounted } from 'vue' | ... | @@ -11,6 +11,7 @@ import { ref, provide, inject, onMounted } from 'vue' |
| 11 | import { logoutAPI, getUserInfoAPI } from '@/api/users' | 11 | import { logoutAPI, getUserInfoAPI } from '@/api/users' |
| 12 | import { getAuthInfoAPI } from '@/api/auth' | 12 | import { getAuthInfoAPI } from '@/api/auth' |
| 13 | import { clearAuthHeaders, setAuthHeaders } from '@/utils/axios' | 13 | import { clearAuthHeaders, setAuthHeaders } from '@/utils/axios' |
| 14 | +import { applyUserInfoAuth, getUserInfoFromStorage, removeUserInfoFromStorage } from '@/utils/auth_user_info' | ||
| 14 | 15 | ||
| 15 | // 创建认证上下文的Symbol key,用于provide/inject依赖注入 | 16 | // 创建认证上下文的Symbol key,用于provide/inject依赖注入 |
| 16 | // 使用Symbol确保key的唯一性,避免命名冲突 | 17 | // 使用Symbol确保key的唯一性,避免命名冲突 |
| ... | @@ -68,8 +69,8 @@ export function provideAuth() { | ... | @@ -68,8 +69,8 @@ export function provideAuth() { |
| 68 | currentUser.value = { ...data.user, ...data.checkin } | 69 | currentUser.value = { ...data.user, ...data.checkin } |
| 69 | localStorage.setItem('currentUser', JSON.stringify(currentUser.value)) | 70 | localStorage.setItem('currentUser', JSON.stringify(currentUser.value)) |
| 70 | // 重新设置认证头 | 71 | // 重新设置认证头 |
| 71 | - const userInfo = JSON.parse(localStorage.getItem('user_info') || '{}') | 72 | + const userInfo = getUserInfoFromStorage() |
| 72 | - if (userInfo.user_id && userInfo.HTTP_USER_TOKEN) { | 73 | + if (userInfo && userInfo.user_id && userInfo.HTTP_USER_TOKEN) { |
| 73 | setAuthHeaders(userInfo.user_id, userInfo.HTTP_USER_TOKEN) | 74 | setAuthHeaders(userInfo.user_id, userInfo.HTTP_USER_TOKEN) |
| 74 | } | 75 | } |
| 75 | } else { | 76 | } else { |
| ... | @@ -80,14 +81,14 @@ export function provideAuth() { | ... | @@ -80,14 +81,14 @@ export function provideAuth() { |
| 80 | if(code) { | 81 | if(code) { |
| 81 | // 如果接口返回了 user_info,先保存 | 82 | // 如果接口返回了 user_info,先保存 |
| 82 | if (data.user_info) { | 83 | if (data.user_info) { |
| 83 | - localStorage.setItem('user_info', JSON.stringify(data.user_info)) | 84 | + applyUserInfoAuth(data.user_info, { set_auth_headers: setAuthHeaders }) |
| 84 | } | 85 | } |
| 85 | 86 | ||
| 86 | // 查询用户是否授权或已登录 | 87 | // 查询用户是否授权或已登录 |
| 87 | if (data.openid_has || data?.user?.id) { | 88 | if (data.openid_has || data?.user?.id) { |
| 88 | // 重新设置认证头 | 89 | // 重新设置认证头 |
| 89 | - const userInfo = JSON.parse(localStorage.getItem('user_info') || '{}') | 90 | + const userInfo = getUserInfoFromStorage() |
| 90 | - if (userInfo.user_id && userInfo.HTTP_USER_TOKEN) { | 91 | + if (userInfo && userInfo.user_id && userInfo.HTTP_USER_TOKEN) { |
| 91 | setAuthHeaders(userInfo.user_id, userInfo.HTTP_USER_TOKEN) | 92 | setAuthHeaders(userInfo.user_id, userInfo.HTTP_USER_TOKEN) |
| 92 | } | 93 | } |
| 93 | 94 | ||
| ... | @@ -144,7 +145,7 @@ export function provideAuth() { | ... | @@ -144,7 +145,7 @@ export function provideAuth() { |
| 144 | currentUser.value = null | 145 | currentUser.value = null |
| 145 | // 清理本地存储的用户信息和登录时间戳 | 146 | // 清理本地存储的用户信息和登录时间戳 |
| 146 | localStorage.removeItem('currentUser') | 147 | localStorage.removeItem('currentUser') |
| 147 | - localStorage.removeItem('user_info') | 148 | + removeUserInfoFromStorage() |
| 148 | // localStorage.removeItem('loginTimestamp') | 149 | // localStorage.removeItem('loginTimestamp') |
| 149 | // 清除认证请求头 | 150 | // 清除认证请求头 |
| 150 | clearAuthHeaders() | 151 | clearAuthHeaders() |
| ... | @@ -154,7 +155,7 @@ export function provideAuth() { | ... | @@ -154,7 +155,7 @@ export function provideAuth() { |
| 154 | // 即使API调用失败,也要清理本地状态 | 155 | // 即使API调用失败,也要清理本地状态 |
| 155 | currentUser.value = null | 156 | currentUser.value = null |
| 156 | localStorage.removeItem('currentUser') | 157 | localStorage.removeItem('currentUser') |
| 157 | - localStorage.removeItem('user_info') | 158 | + removeUserInfoFromStorage() |
| 158 | clearAuthHeaders() | 159 | clearAuthHeaders() |
| 159 | } | 160 | } |
| 160 | } | 161 | } | ... | ... |
| ... | @@ -25,5 +25,97 @@ export const applyUserInfoAuth = (input, options = {}) => { | ... | @@ -25,5 +25,97 @@ export const applyUserInfoAuth = (input, options = {}) => { |
| 25 | storage.setItem('user_info', JSON.stringify(user_info || {})) | 25 | storage.setItem('user_info', JSON.stringify(user_info || {})) |
| 26 | } | 26 | } |
| 27 | 27 | ||
| 28 | + if (storage === globalThis.localStorage) { | ||
| 29 | + cached_user_info_str = JSON.stringify(user_info || {}) | ||
| 30 | + cached_user_info = user_info || {} | ||
| 31 | + } | ||
| 32 | + | ||
| 28 | return true | 33 | return true |
| 29 | } | 34 | } |
| 35 | + | ||
| 36 | +let cached_user_info_str = null | ||
| 37 | +let cached_user_info = null | ||
| 38 | + | ||
| 39 | +const safeParse = (text) => { | ||
| 40 | + try { | ||
| 41 | + return JSON.parse(text) | ||
| 42 | + } catch (e) { | ||
| 43 | + return null | ||
| 44 | + } | ||
| 45 | +} | ||
| 46 | + | ||
| 47 | +/** | ||
| 48 | + * 从存储中获取用户信息 | ||
| 49 | + * @param {*} options 选项对象,包含 storage 字段 | ||
| 50 | + * @returns 如果用户信息存在且有效,则返回用户信息对象;否则返回 null | ||
| 51 | + */ | ||
| 52 | +export const getUserInfoFromStorage = (options = {}) => { | ||
| 53 | + const storage = Object.prototype.hasOwnProperty.call(options, 'storage') ? options.storage : globalThis.localStorage | ||
| 54 | + if (!storage || typeof storage.getItem !== 'function') { | ||
| 55 | + return null | ||
| 56 | + } | ||
| 57 | + | ||
| 58 | + const raw = storage.getItem('user_info') | ||
| 59 | + if (!raw) { | ||
| 60 | + if (storage === globalThis.localStorage) { | ||
| 61 | + cached_user_info_str = null | ||
| 62 | + cached_user_info = null | ||
| 63 | + } | ||
| 64 | + return null | ||
| 65 | + } | ||
| 66 | + | ||
| 67 | + if (storage === globalThis.localStorage && cached_user_info_str === raw && cached_user_info) { | ||
| 68 | + return cached_user_info | ||
| 69 | + } | ||
| 70 | + | ||
| 71 | + const parsed = safeParse(raw) | ||
| 72 | + if (!parsed || typeof parsed !== 'object') { | ||
| 73 | + if (storage === globalThis.localStorage) { | ||
| 74 | + cached_user_info_str = null | ||
| 75 | + cached_user_info = null | ||
| 76 | + } | ||
| 77 | + return null | ||
| 78 | + } | ||
| 79 | + | ||
| 80 | + if (storage === globalThis.localStorage) { | ||
| 81 | + cached_user_info_str = raw | ||
| 82 | + cached_user_info = parsed | ||
| 83 | + } | ||
| 84 | + | ||
| 85 | + return parsed | ||
| 86 | +} | ||
| 87 | + | ||
| 88 | +/** | ||
| 89 | + * 从存储中移除用户信息 | ||
| 90 | + * @param {*} options 选项对象,包含 storage 字段 | ||
| 91 | + */ | ||
| 92 | +export const removeUserInfoFromStorage = (options = {}) => { | ||
| 93 | + const storage = Object.prototype.hasOwnProperty.call(options, 'storage') ? options.storage : globalThis.localStorage | ||
| 94 | + if (storage && typeof storage.removeItem === 'function') { | ||
| 95 | + storage.removeItem('user_info') | ||
| 96 | + } | ||
| 97 | + if (storage === globalThis.localStorage) { | ||
| 98 | + cached_user_info_str = null | ||
| 99 | + cached_user_info = null | ||
| 100 | + } | ||
| 101 | +} | ||
| 102 | + | ||
| 103 | +/** | ||
| 104 | + * 从用户信息中提取认证头信息 | ||
| 105 | + * @param {*} user_info 用户信息对象,包含 user_id 和 HTTP_USER_TOKEN 字段 | ||
| 106 | + * @returns 如果用户信息有效,则返回包含 User-Id 和 User-Token 字段的对象;否则返回空对象 | ||
| 107 | + */ | ||
| 108 | +export const getAuthHeadersFromUserInfo = (user_info) => { | ||
| 109 | + if (!user_info || typeof user_info !== 'object') { | ||
| 110 | + return {} | ||
| 111 | + } | ||
| 112 | + const user_id = user_info.user_id | ||
| 113 | + const user_token = user_info.HTTP_USER_TOKEN | ||
| 114 | + if (!user_id || !user_token) { | ||
| 115 | + return {} | ||
| 116 | + } | ||
| 117 | + return { | ||
| 118 | + 'User-Id': user_id, | ||
| 119 | + 'User-Token': user_token | ||
| 120 | + } | ||
| 121 | +} | ... | ... |
| ... | @@ -9,6 +9,7 @@ | ... | @@ -9,6 +9,7 @@ |
| 9 | import axios from 'axios'; | 9 | import axios from 'axios'; |
| 10 | import router from '@/router'; | 10 | import router from '@/router'; |
| 11 | import { checkAuth } from '@/router/guards' | 11 | import { checkAuth } from '@/router/guards' |
| 12 | +import { getUserInfoFromStorage, removeUserInfoFromStorage } from '@/utils/auth_user_info' | ||
| 12 | // import qs from 'Qs' | 13 | // import qs from 'Qs' |
| 13 | // import { strExist } from '@/utils/tools' | 14 | // import { strExist } from '@/utils/tools' |
| 14 | 15 | ||
| ... | @@ -47,10 +48,10 @@ axios.interceptors.request.use( | ... | @@ -47,10 +48,10 @@ axios.interceptors.request.use( |
| 47 | * 动态获取 user_info 并设置到请求头 | 48 | * 动态获取 user_info 并设置到请求头 |
| 48 | * 确保每个请求都带上最新的 user_info | 49 | * 确保每个请求都带上最新的 user_info |
| 49 | */ | 50 | */ |
| 50 | - const user_info = localStorage.getItem('user_info') ? JSON.parse(localStorage.getItem('user_info')) : {}; | 51 | + const user_info = getUserInfoFromStorage() |
| 51 | if (user_info) { | 52 | if (user_info) { |
| 52 | - config.headers['User-Id'] = user_info.user_id; | 53 | + config.headers['User-Id'] = user_info.user_id |
| 53 | - config.headers['User-Token'] = user_info.HTTP_USER_TOKEN; | 54 | + config.headers['User-Token'] = user_info.HTTP_USER_TOKEN |
| 54 | } | 55 | } |
| 55 | 56 | ||
| 56 | // const url_params = parseQueryString(location.href); | 57 | // const url_params = parseQueryString(location.href); |
| ... | @@ -88,6 +89,7 @@ axios.interceptors.response.use( | ... | @@ -88,6 +89,7 @@ axios.interceptors.response.use( |
| 88 | if (need_login_redirect) { | 89 | if (need_login_redirect) { |
| 89 | // 仅在受限页面触发登录重定向 | 90 | // 仅在受限页面触发登录重定向 |
| 90 | localStorage.removeItem('currentUser'); | 91 | localStorage.removeItem('currentUser'); |
| 92 | + removeUserInfoFromStorage() | ||
| 91 | clearAuthHeaders(); | 93 | clearAuthHeaders(); |
| 92 | const current_path = to.fullPath; | 94 | const current_path = to.fullPath; |
| 93 | router.push(`/login?redirect=${encodeURIComponent(current_path)}`); | 95 | router.push(`/login?redirect=${encodeURIComponent(current_path)}`); | ... | ... |
-
Please register or login to post a comment