优化 JWT 令牌的存储和使用逻辑;调整布局样式和组件属性

This commit is contained in:
2025-04-06 23:09:48 +08:00
parent d5c9e663da
commit eb306b66b0
14 changed files with 144 additions and 140 deletions

View File

@@ -1,80 +1,84 @@
import { QueryGetAPI, QueryPostAPI, QueryPostAPIWithParams } from '@/api/query'
import { ACCOUNT_API_URL, VTSURU_API_URL } from '@/data/constants'
import { useLocalStorage } from '@vueuse/core'
import { isSameDay } from 'date-fns'
import { createDiscreteApi } from 'naive-ui'
import { ref } from 'vue'
import { APIRoot, AccountInfo, FunctionTypes } from './api-models'
import { QueryGetAPI, QueryPostAPI, QueryPostAPIWithParams } from '@/api/query';
import { ACCOUNT_API_URL, VTSURU_API_URL } from '@/data/constants';
import { isSameDay } from 'date-fns';
import { createDiscreteApi } from 'naive-ui';
import { ref } from 'vue';
import { APIRoot, AccountInfo, FunctionTypes } from './api-models';
import { StorageSerializers } from '@vueuse/core';
export const ACCOUNT = ref<AccountInfo>({} as AccountInfo)
export const isLoadingAccount = ref(true)
export const ACCOUNT = ref<AccountInfo>({} as AccountInfo);
export const isLoadingAccount = ref(true);
export const isLoggedIn = computed<boolean>(() => {
return ACCOUNT.value.id > 0
})
return ACCOUNT.value.id > 0;
});
const { message } = createDiscreteApi(['message'])
const cookie = useLocalStorage('JWT_Token', '')
const cookieRefreshDate = useLocalStorage('JWT_Token_Last_Refresh', 0)
const { message } = createDiscreteApi(['message']);
export const cookie = useLocalStorage('Cookie', {cookie: '', refreshDate: 0}, { serializer: StorageSerializers.object });
export async function GetSelfAccount(token?: string) {
if (cookie.value || token) {
const result = await Self(token)
if (cookie.value.cookie || token) {
const result = await Self(token);
if (result.code == 200) {
if (!ACCOUNT.value.id) {
ACCOUNT.value = result.data
ACCOUNT.value = result.data;
} else {
result.data.settings = ACCOUNT.value.settings
ACCOUNT.value = result.data
result.data.settings = ACCOUNT.value.settings;
ACCOUNT.value = result.data;
}
isLoadingAccount.value = false
isLoadingAccount.value = false;
//console.log('[vtsuru] 已获取账户信息')
if (!isSameDay(new Date(), cookieRefreshDate.value)) {
refreshCookie(token)
if (!cookie.value.cookie || !isSameDay(new Date(), cookie.value!.refreshDate)) {
refreshCookie(token);
}
return result.data
return result.data;
} else if (result.code == 401) {
localStorage.removeItem('JWT_Token')
console.warn('[vtsuru] Cookie 已失效, 需要重新登陆')
message.error('Cookie 已失效, 需要重新登陆')
setTimeout(() => {
location.reload()
}, 1500)
localStorage.removeItem('JWT_Token');
if (!token) {
cookie.value = undefined;
console.warn('[vtsuru] Cookie 已失效, 需要重新登陆');
message.error('Cookie 已失效, 需要重新登陆');
setTimeout(() => {
location.reload();
}, 1500);
}
} else {
console.warn('[vtsuru] ' + result.message)
message.error(result.message)
console.warn('[vtsuru] ' + result.message);
message.error(result.message);
}
}
isLoadingAccount.value = false
isLoadingAccount.value = false;
}
export function UpdateAccountLoop() {
setInterval(() => {
if (ACCOUNT.value && window.$route?.name != 'question-display') {
// 防止在问题详情页刷新
GetSelfAccount()
GetSelfAccount();
}
}, 60 * 1000)
}, 60 * 1000);
}
function refreshCookie(token?: string) {
QueryPostAPIWithParams<string>(`${ACCOUNT_API_URL}refresh-token`, { token }).then((data) => {
if (data.code == 200) {
cookie.value = data.data
cookieRefreshDate.value = Date.now()
console.log('[vtsuru] 已刷新Cookie')
cookie.value = {
cookie: data.data,
refreshDate: new Date().getTime()
};
console.log('[vtsuru] 已刷新Cookie');
}
})
});
}
export async function SaveAccountSettings() {
return await QueryPostAPI(
ACCOUNT_API_URL + 'update-setting',
ACCOUNT.value?.settings
)
);
}
export async function SaveEnableFunctions(functions: FunctionTypes[]) {
return await QueryPostAPI(
ACCOUNT_API_URL + 'update-enable-functions',
functions
)
);
}
export async function SaveSetting(
name:
@@ -94,44 +98,44 @@ export async function SaveSetting(
name
},
setting
)
return result.message
);
return result.message;
}
export async function UpdateFunctionEnable(func: FunctionTypes) {
if (ACCOUNT.value) {
const oldValue = JSON.parse(
JSON.stringify(ACCOUNT.value.settings.enableFunctions)
)
);
if (ACCOUNT.value?.settings.enableFunctions.includes(func)) {
ACCOUNT.value.settings.enableFunctions =
ACCOUNT.value.settings.enableFunctions.filter((f) => f != func)
ACCOUNT.value.settings.enableFunctions.filter((f) => f != func);
} else {
ACCOUNT.value.settings.enableFunctions.push(func)
ACCOUNT.value.settings.enableFunctions.push(func);
}
await SaveEnableFunctions(ACCOUNT.value?.settings.enableFunctions)
.then((data) => {
if (data.code == 200) {
message.success(
`${ACCOUNT.value?.settings.enableFunctions.includes(func) ? '启用' : '禁用'}`
)
);
} else {
if (ACCOUNT.value) {
ACCOUNT.value.settings.enableFunctions = oldValue
ACCOUNT.value.settings.enableFunctions = oldValue;
}
message.error(
`${ACCOUNT.value?.settings.enableFunctions.includes(func) ? '启用' : '禁用'}失败: ${data.message}`
)
);
}
})
.catch((err) => {
message.error(
`${ACCOUNT.value?.settings.enableFunctions.includes(func) ? '启用' : '禁用'}失败: ${err}`
)
})
);
});
}
}
export function useAccount() {
return ACCOUNT
return ACCOUNT;
}
export async function Register(
@@ -145,7 +149,7 @@ export async function Register(
email,
password,
token
})
});
}
export async function Login(
@@ -155,10 +159,10 @@ export async function Login(
return QueryPostAPI<string>(`${ACCOUNT_API_URL}login`, {
nameOrEmail,
password
})
});
}
export async function Self(token?: string): Promise<APIRoot<AccountInfo>> {
return QueryPostAPIWithParams<AccountInfo>(`${ACCOUNT_API_URL}self`, token ? { token } : undefined)
return QueryPostAPIWithParams<AccountInfo>(`${ACCOUNT_API_URL}self`, token ? { token } : undefined);
}
export async function AddBiliBlackList(
id: number,
@@ -167,70 +171,70 @@ export async function AddBiliBlackList(
return QueryGetAPI<AccountInfo>(`${ACCOUNT_API_URL}black-list/add-bili`, {
id: id,
name: name
})
});
}
export async function DelBiliBlackList(id: number): Promise<APIRoot<unknown>> {
return QueryGetAPI<AccountInfo>(`${ACCOUNT_API_URL}black-list/del-bili`, {
id: id
})
});
}
export async function DelBlackList(id: number): Promise<APIRoot<unknown>> {
return QueryGetAPI<AccountInfo>(`${ACCOUNT_API_URL}black-list/del`, {
id: id
})
});
}
export function downloadConfigDirect(name: string) {
return QueryGetAPI<string>(VTSURU_API_URL + 'get-config', {
name: name
})
});
}
export type ConfigStatus = 'success' | 'error' | 'notfound'
export type ConfigStatus = 'success' | 'error' | 'notfound';
export async function DownloadConfig<T>(name: string, id?: number): Promise<
| {
msg: undefined
status: ConfigStatus
data: T
}
msg: undefined;
status: ConfigStatus;
data: T;
}
| {
msg: string
status: ConfigStatus
data: undefined
}
msg: string;
status: ConfigStatus;
data: undefined;
}
> {
try {
const resp = await QueryGetAPI<string>(VTSURU_API_URL + (id ? 'get-user-config' : 'get-config'), {
name: name,
id: id
})
});
if (resp.code == 200) {
console.log('已获取配置文件: ' + name)
console.log('已获取配置文件: ' + name);
return {
msg: undefined,
status: 'success',
data: JSON.parse(resp.data) as T
}
};
} else if (resp.code == 404) {
console.error(`未找到名为 ${name} 的配置文件`)
console.error(`未找到名为 ${name} 的配置文件`);
return {
msg: `未找到名为 ${name} 的配置文件, 需要先上传`,
status: 'notfound',
data: undefined
}
};
} else {
console.error(`无法获取配置文件 [${name}]: ` + resp.message)
console.error(`无法获取配置文件 [${name}]: ` + resp.message);
return {
msg: `无法获取配置文件 [${name}]: ` + resp.message,
status: 'error',
data: undefined
}
};
}
} catch (err) {
console.error(`无法获取配置文件 [${name}]: ` + err)
console.error(`无法获取配置文件 [${name}]: ` + err);
return {
msg: `无法获取配置文件 [${name}]: ` + err,
status: 'error',
data: undefined
}
};
}
}
export async function UploadConfig(name: string, data: unknown) {
@@ -238,70 +242,70 @@ export async function UploadConfig(name: string, data: unknown) {
const resp = await QueryPostAPI(VTSURU_API_URL + 'set-config', {
name: name,
json: JSON.stringify(data)
})
});
if (resp.code == 200) {
console.log('已保存配置文件至服务器:' + name)
return true
console.log('已保存配置文件至服务器:' + name);
return true;
} else {
console.error('保存失败: ' + resp.message)
console.error('保存失败: ' + resp.message);
}
} catch (err) {
console.error(`保存配置文件失败: ` + err)
console.error(`保存配置文件失败: ` + err);
}
return false
return false;
}
export async function EnableFunction(func: FunctionTypes) {
if (ACCOUNT.value) {
if (ACCOUNT.value.settings.enableFunctions.includes(func)) {
return true
return true;
} else {
ACCOUNT.value.settings.enableFunctions.push(func)
ACCOUNT.value.settings.enableFunctions.push(func);
if (await updateFunctionEnable()) {
return true
return true;
} else {
ACCOUNT.value.settings.enableFunctions.splice(
ACCOUNT.value.settings.enableFunctions.indexOf(func),
1
)
return false
);
return false;
}
}
}
return false
return false;
}
export async function DisableFunction(func: FunctionTypes) {
if (ACCOUNT.value) {
if (!ACCOUNT.value.settings.enableFunctions.includes(func)) {
return true
return true;
} else {
ACCOUNT.value.settings.enableFunctions.splice(
ACCOUNT.value.settings.enableFunctions.indexOf(func),
1
)
);
if (await updateFunctionEnable()) {
return true
return true;
} else {
ACCOUNT.value.settings.enableFunctions.push(func)
return false
ACCOUNT.value.settings.enableFunctions.push(func);
return false;
}
}
}
return false
return false;
}
async function updateFunctionEnable() {
if (ACCOUNT.value) {
try {
const data = await SaveEnableFunctions(
ACCOUNT.value.settings.enableFunctions
)
);
if (data.code == 200) {
return true
return true;
} else {
return false
return false;
}
} catch (err) {
console.log(err)
return false
console.log(err);
return false;
}
}
}

View File

@@ -2,8 +2,7 @@
import { apiFail } from '@/data/constants'
import { useLocalStorage } from '@vueuse/core'
import { APIRoot, PaginationResponse } from './api-models'
const cookie = useLocalStorage('JWT_Token', '')
import { cookie } from './account';
export async function QueryPostAPI<T>(
urlString: string,
@@ -58,7 +57,7 @@ async function QueryPostAPIWithParamsInternal<T>(
headers.forEach((header) => {
h[header[0]] = header[1]
})
if (cookie.value) h['Authorization'] = `Bearer ${cookie.value}`
if (cookie.value.cookie) h['Authorization'] = `Bearer ${cookie.value.cookie}`
h['Content-Type'] = contentType
return await QueryAPIInternal<T>(url, {
@@ -112,8 +111,8 @@ async function QueryGetAPIInternal<T>(
headers.forEach((header) => {
h[header[0]] = header[1]
})
if (cookie.value) {
h['Authorization'] = `Bearer ${cookie.value}`
if (cookie.value.cookie) {
h['Authorization'] = `Bearer ${cookie.value.cookie}`
}
return await QueryAPIInternal<T>(url, { method: 'get', headers: h })
} catch (err) {
@@ -163,5 +162,5 @@ export async function QueryGetPaginationAPI<T>(
return await QueryGetAPIInternal<PaginationResponse<T>>(urlString, params)
}
export function GetHeaders(): [string, string][] {
return [['Authorization', `Bearer ${cookie.value}`]]
return [['Authorization', `Bearer ${cookie.value?.cookie}`]]
}