hookehuyr

refactor(auth): 重构用户信息存储逻辑,添加缓存和工具函数

将直接操作 localStorage 的用户信息逻辑封装到工具函数中
添加缓存机制减少 localStorage 读取次数
提供统一的用户信息获取、设置和删除方法
...@@ -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)}`);
......