Files
----/前端源码/uni-app/utils/auth.ts

175 lines
4.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 登录状态管理工具
*/
import router from '@/router';
const TOKEN_KEY = 'token';
const USER_INFO_KEY = 'userInfo';
const TOKEN_EXPIRE_TIME_KEY = 'tokenExpireTime';
const normalizeAvatarUrl = (avatar: any): any => {
if (typeof avatar !== 'string') return avatar;
const url = avatar.trim();
if (!url) return url;
if (!url.startsWith('http://')) return url;
const host = url.slice('http://'.length).split('/')[0] || '';
const isLocalhost = host.startsWith('localhost') || host.startsWith('127.0.0.1');
const isPrivateIp =
host.startsWith('10.') ||
host.startsWith('192.168.') ||
/^172\.(1[6-9]|2\d|3[0-1])\./.test(host);
if (isLocalhost || isPrivateIp) return url;
return 'https://' + url.slice('http://'.length);
};
const normalizeUserInfo = (userInfo: any): any => {
if (!userInfo || typeof userInfo !== 'object') return userInfo;
const next = { ...userInfo };
if ('avatar' in next) {
next.avatar = normalizeAvatarUrl((next as any).avatar);
}
return next;
};
/**
* 获取 token
*/
export const getToken = (): string | null => {
try {
return localStorage.getItem(TOKEN_KEY) || null;
} catch (e) {
console.error('获取 token 失败:', e);
return null;
}
};
/**
* 设置 token
*/
export const setToken = (token: string, expireTime?: number): void => {
try {
localStorage.setItem(TOKEN_KEY, token);
if (expireTime) {
localStorage.setItem(TOKEN_EXPIRE_TIME_KEY, String(expireTime));
}
} catch (e) {
console.error('设置 token 失败:', e);
}
};
/**
* 清除 token
*/
export const clearToken = (): void => {
try {
localStorage.removeItem(TOKEN_KEY);
localStorage.removeItem(TOKEN_EXPIRE_TIME_KEY);
localStorage.removeItem(USER_INFO_KEY);
} catch (e) {
console.error('清除 token 失败:', e);
}
};
/**
* 检查 token 是否存在
*/
export const hasToken = (): boolean => {
return !!getToken();
};
/**
* 检查 token 是否过期
* @param expireTime token 过期时间戳(毫秒),如果不传则从存储中读取
*/
export const isTokenExpired = (expireTime?: number): boolean => {
try {
const expireStr = expireTime ? String(expireTime) : localStorage.getItem(TOKEN_EXPIRE_TIME_KEY);
if (!expireStr) {
// 如果没有过期时间,认为 token 有效(由后端验证)
return false;
}
const expire = Number(expireStr);
return Date.now() >= expire;
} catch (e) {
console.error('检查 token 过期失败:', e);
return false;
}
};
/**
* 检查是否已登录token 存在且未过期)
*/
export const isLoggedIn = (): boolean => {
return hasToken() && !isTokenExpired();
};
/**
* 获取用户信息
*/
export const getUserInfo = (): any | null => {
try {
const v = localStorage.getItem(USER_INFO_KEY);
if (!v) return null;
return normalizeUserInfo(JSON.parse(v));
} catch (e) {
console.error('获取用户信息失败:', e);
return null;
}
};
/**
* 设置用户信息
*/
export const setUserInfo = (userInfo: any): void => {
try {
localStorage.setItem(USER_INFO_KEY, JSON.stringify(normalizeUserInfo(userInfo)));
} catch (e) {
console.error('设置用户信息失败:', e);
}
};
/**
* 跳转到登录页
* @param force 为 true 时即使当前已在 /login 也 replace 一次(用于退出登录后刷新登录态)
*/
export const navigateToLogin = (options?: { redirect?: string; force?: boolean }): void => {
try {
const currentRoute = router.currentRoute.value.path;
if (options?.force || currentRoute !== '/login') {
const redirect = options?.redirect ?? (currentRoute !== '/login' ? currentRoute : '/');
router.replace({
path: '/login',
query: { redirect: encodeURIComponent(redirect) }
});
}
} catch (e) {
console.error('跳转登录页失败:', e);
}
};
/**
* 退出登录:仅前端清空 token / 用户信息并进入登录页(不请求后端)
*/
export const logout = (): void => {
clearToken();
navigateToLogin({ force: true, redirect: '/' });
};
/**
* 需要登录的页面路径列表(白名单外的页面都需要登录)
*/
const LOGIN_WHITELIST = ['/login'];
/**
* 检查页面是否需要登录
*/
export const isPageRequireLogin = (path: string): boolean => {
return !LOGIN_WHITELIST.some((whitelistPath) => path.includes(whitelistPath));
};