17 changed files with 848 additions and 162 deletions
After Width: | Height: | Size: 1.3 MiB |
@ -1,5 +1,48 @@ |
|||
export const AUTH_CONSTANTS = { |
|||
// 存储键名
|
|||
STORAGE_KEYS: { |
|||
ACCESS_TOKEN: 'accessToken', |
|||
REFRESH_TOKEN: 'refreshToken', |
|||
TOKEN_EXPIRY: 'tokenExpiry', |
|||
REMEMBER_ME: 'rememberMe', |
|||
LOGIN_ATTEMPTS: 'loginAttempts', |
|||
LAST_LOGIN_ATTEMPT: 'lastLoginAttempt' |
|||
}, |
|||
|
|||
// 认证配置
|
|||
AUTH_CONFIG: { |
|||
MAX_LOGIN_ATTEMPTS: 5, |
|||
LOGIN_ATTEMPTS_RESET_TIME: 30 * 60 * 1000, // 30分钟
|
|||
TOKEN_EXPIRY_TIME: 24 * 60 * 60 * 1000, // 24小时
|
|||
TOKEN_REFRESH_THRESHOLD: 5 * 60 * 1000, // 5分钟
|
|||
}, |
|||
|
|||
// 默认权限
|
|||
DEFAULT_PERMISSIONS: { |
|||
VIEW_DASHBOARD: true, |
|||
MANAGE_USERS: false, |
|||
MANAGE_ROLES: false, |
|||
MANAGE_PERMISSIONS: false |
|||
}, |
|||
|
|||
MESSAGES: { |
|||
LOGIN_SUCCESS: '登录成功', |
|||
LOGIN_FAILED: '登录失败,请检查用户名和密码', |
|||
LOGOUT_SUCCESS: '已成功退出登录', |
|||
LOGOUT_FAILED: '退出登录失败', |
|||
TOKEN_REFRESHED: '令牌已刷新', |
|||
TOKEN_REFRESH_FAILED: '令牌刷新失败,请重新登录', |
|||
USER_FETCHED: '已获取用户信息', |
|||
USER_FETCH_FAILED: '获取用户信息失败', |
|||
INVALID_CREDENTIALS: '用户名或密码错误', |
|||
ACCOUNT_LOCKED: '账户已被锁定,请稍后再试', |
|||
TOKEN_EXPIRED: '登录已过期,请重新登录', |
|||
NETWORK_ERROR: '网络错误,请检查网络连接', |
|||
UNKNOWN_ERROR: '发生未知错误,请稍后重试' |
|||
} |
|||
} as const; |
|||
|
|||
export const DEFAULT_CREDENTIALS = { |
|||
username: 'zhangsan', |
|||
email: 'zhangsan@example.com', |
|||
password: 'P@ssw0rd!' |
|||
}; |
@ -0,0 +1,20 @@ |
|||
import { useEffect } from 'react'; |
|||
import { Dispatch } from 'react'; |
|||
import { AuthAction } from '@/types/auth'; |
|||
import { authService } from '@/services/authService'; |
|||
|
|||
export function useAuthInit(dispatch: Dispatch<AuthAction>) { |
|||
useEffect(() => { |
|||
console.log('[useAuthInit] 开始初始化认证状态'); |
|||
const initAuth = async () => { |
|||
try { |
|||
console.log('[useAuthInit] 调用 initializeAuth'); |
|||
await authService.initializeAuth(dispatch); |
|||
console.log('[useAuthInit] initializeAuth 完成'); |
|||
} catch (error) { |
|||
console.error('[useAuthInit] 初始化失败', error); |
|||
} |
|||
}; |
|||
initAuth(); |
|||
}, [dispatch]); |
|||
} |
@ -0,0 +1,8 @@ |
|||
import { useEffect } from 'react'; |
|||
import { User } from '@/types/auth'; |
|||
|
|||
export function useAuthSync(user: User | null, setGlobalUser: (user: User | null) => void) { |
|||
useEffect(() => { |
|||
setGlobalUser(user); |
|||
}, [user, setGlobalUser]); |
|||
} |
@ -0,0 +1,82 @@ |
|||
import { LoginRequest, LoginResponse, User, OperationResult } from '@/types/auth'; |
|||
import { httpClient } from '@/lib/http-client'; |
|||
import { AUTH_CONSTANTS } from '@/constants/auth'; |
|||
|
|||
export interface ApiService { |
|||
login: (request: LoginRequest) => Promise<OperationResult<LoginResponse>>; |
|||
refreshToken: (refreshToken: string) => Promise<OperationResult<LoginResponse>>; |
|||
logout: () => Promise<OperationResult<void>>; |
|||
getCurrentUser: () => Promise<OperationResult<User>>; |
|||
} |
|||
|
|||
class ApiError extends Error { |
|||
constructor(message: string, public statusCode?: number) { |
|||
super(message); |
|||
this.name = 'ApiError'; |
|||
} |
|||
} |
|||
|
|||
export const apiService: ApiService = { |
|||
login: async (request: LoginRequest): Promise<OperationResult<LoginResponse>> => { |
|||
try { |
|||
const response = await httpClient.post<LoginResponse>('/Auth/Login', request); |
|||
return { |
|||
success: true, |
|||
data: response.data, |
|||
message: AUTH_CONSTANTS.MESSAGES.LOGIN_SUCCESS |
|||
}; |
|||
} catch (error: any) { |
|||
return { |
|||
success: false, |
|||
message: error.response?.data?.message || AUTH_CONSTANTS.MESSAGES.LOGIN_FAILED |
|||
}; |
|||
} |
|||
}, |
|||
|
|||
refreshToken: async (refreshToken: string): Promise<OperationResult<LoginResponse>> => { |
|||
try { |
|||
const response = await httpClient.post<LoginResponse>('/Auth/RefreshToken', { refreshToken }); |
|||
return { |
|||
success: true, |
|||
data: response.data, |
|||
message: AUTH_CONSTANTS.MESSAGES.TOKEN_REFRESHED |
|||
}; |
|||
} catch (error: any) { |
|||
return { |
|||
success: false, |
|||
message: error.response?.data?.message || AUTH_CONSTANTS.MESSAGES.TOKEN_REFRESH_FAILED |
|||
}; |
|||
} |
|||
}, |
|||
|
|||
logout: async (): Promise<OperationResult<void>> => { |
|||
try { |
|||
await httpClient.post('/Auth/Logout'); |
|||
return { |
|||
success: true, |
|||
message: AUTH_CONSTANTS.MESSAGES.LOGOUT_SUCCESS |
|||
}; |
|||
} catch (error: any) { |
|||
return { |
|||
success: false, |
|||
message: error.response?.data?.message || AUTH_CONSTANTS.MESSAGES.LOGOUT_FAILED |
|||
}; |
|||
} |
|||
}, |
|||
|
|||
getCurrentUser: async (): Promise<OperationResult<User>> => { |
|||
try { |
|||
const response = await httpClient.get<User>('/Users/CurrentUser'); |
|||
return { |
|||
success: true, |
|||
data: response.data, |
|||
message: AUTH_CONSTANTS.MESSAGES.USER_FETCHED |
|||
}; |
|||
} catch (error: any) { |
|||
return { |
|||
success: false, |
|||
message: error.response?.data?.message || AUTH_CONSTANTS.MESSAGES.USER_FETCH_FAILED |
|||
}; |
|||
} |
|||
} |
|||
}; |
@ -1,55 +1,207 @@ |
|||
import { LoginRequest, LoginResponse, OperationResult } from '@/types/auth'; |
|||
import { httpClient } from '@/lib/http-client'; |
|||
import { LoginRequest, User, OperationResult, AuthAction } from '@/types/auth'; |
|||
import { storageService } from './storageService'; |
|||
import { apiService } from '@/services/apiService'; |
|||
import { AUTH_CONSTANTS } from '@/constants/auth'; |
|||
|
|||
export const authService = { |
|||
async login(request: LoginRequest): Promise<OperationResult<LoginResponse>> { |
|||
try { |
|||
const response = await httpClient.post<LoginResponse>('/Auth/Login', request); |
|||
return response; |
|||
} catch (error: any) { |
|||
return { |
|||
successMessage: null, |
|||
errorMessages: error.errorMessages || ['登录请求失败,请稍后重试'], |
|||
data: null, |
|||
isSuccess: false, |
|||
}; |
|||
export interface AuthService { |
|||
isTokenExpired: () => boolean; |
|||
checkLoginAttempts: () => boolean; |
|||
updateLoginAttempts: (success: boolean) => void; |
|||
handleLogin: (request: LoginRequest, dispatch: React.Dispatch<AuthAction>) => Promise<void>; |
|||
handleLogout: (dispatch: React.Dispatch<AuthAction>) => Promise<void>; |
|||
handleRefreshToken: (dispatch: React.Dispatch<AuthAction>) => Promise<void>; |
|||
initializeAuth: (dispatch: React.Dispatch<AuthAction>) => Promise<void>; |
|||
} |
|||
|
|||
class AuthError extends Error { |
|||
constructor(message: string) { |
|||
super(message); |
|||
this.name = 'AuthError'; |
|||
} |
|||
} |
|||
|
|||
export const authService: AuthService = { |
|||
isTokenExpired: () => { |
|||
const expiryTime = storageService.getTokenExpiry(); |
|||
if (!expiryTime) return true; |
|||
return Date.now() > parseInt(expiryTime); |
|||
}, |
|||
|
|||
// 刷新token
|
|||
async refreshToken(refreshToken: string): Promise<OperationResult<LoginResponse>> { |
|||
checkLoginAttempts: () => { |
|||
const attempts = storageService.getLoginAttempts(); |
|||
const lastAttempt = storageService.getLastLoginAttempt(); |
|||
const now = Date.now(); |
|||
|
|||
if (attempts >= AUTH_CONSTANTS.AUTH_CONFIG.MAX_LOGIN_ATTEMPTS) { |
|||
if (now - lastAttempt < AUTH_CONSTANTS.AUTH_CONFIG.LOGIN_ATTEMPTS_RESET_TIME) { |
|||
throw new AuthError(AUTH_CONSTANTS.MESSAGES.ACCOUNT_LOCKED); |
|||
} |
|||
storageService.removeLoginAttempts(); |
|||
storageService.removeLastLoginAttempt(); |
|||
} |
|||
return true; |
|||
}, |
|||
|
|||
updateLoginAttempts: (success: boolean) => { |
|||
if (success) { |
|||
storageService.removeLoginAttempts(); |
|||
storageService.removeLastLoginAttempt(); |
|||
} else { |
|||
const attempts = storageService.getLoginAttempts() + 1; |
|||
storageService.setLoginAttempts(attempts); |
|||
storageService.setLastLoginAttempt(Date.now()); |
|||
} |
|||
}, |
|||
|
|||
handleLogin: async (request: LoginRequest, dispatch: React.Dispatch<AuthAction>) => { |
|||
try { |
|||
const response = await httpClient.post<LoginResponse>('/Auth/RefreshToken', { |
|||
refreshToken, |
|||
console.log('[authService] handleLogin start', request); |
|||
dispatch({ type: 'LOGIN_START' }); |
|||
const result = await apiService.login(request); |
|||
console.log('[authService] login result', result); |
|||
if (!result.success) { |
|||
throw new AuthError(result.message || AUTH_CONSTANTS.MESSAGES.LOGIN_FAILED); |
|||
} |
|||
const { accessToken, refreshToken, user } = result.data!; |
|||
const expiryTime = Date.now() + AUTH_CONSTANTS.AUTH_CONFIG.TOKEN_EXPIRY_TIME; |
|||
storageService.setAccessToken(accessToken); |
|||
storageService.setRefreshToken(refreshToken); |
|||
storageService.setTokenExpiry(expiryTime); |
|||
storageService.setRememberMe(request.rememberMe); |
|||
console.log('[authService] tokens saved', { accessToken, refreshToken, expiryTime }); |
|||
dispatch({ |
|||
type: 'LOGIN_SUCCESS', |
|||
payload: { user, accessToken, refreshToken, rememberMe: request.rememberMe } |
|||
}); |
|||
return response; |
|||
} catch (error: any) { |
|||
return { |
|||
successMessage: null, |
|||
errorMessages: error.errorMessages || ['刷新令牌失败,请重新登录'], |
|||
data: null, |
|||
isSuccess: false, |
|||
}; |
|||
console.error('[authService] handleLogin error', error); |
|||
dispatch({ |
|||
type: 'LOGIN_FAILURE', |
|||
payload: { error: error.message || AUTH_CONSTANTS.MESSAGES.UNKNOWN_ERROR } |
|||
}); |
|||
throw error; |
|||
} |
|||
}, |
|||
|
|||
// 登出
|
|||
async logout(): Promise<void> { |
|||
await httpClient.post('/Auth/Logout'); |
|||
handleLogout: async (dispatch: React.Dispatch<AuthAction>) => { |
|||
try { |
|||
console.log('[authService] handleLogout start'); |
|||
const result = await apiService.logout(); |
|||
console.log('[authService] logout result', result); |
|||
if (!result.success) { |
|||
throw new AuthError(result.message || AUTH_CONSTANTS.MESSAGES.LOGOUT_FAILED); |
|||
} |
|||
storageService.clearAuth(); |
|||
console.log('[authService] tokens cleared'); |
|||
dispatch({ type: 'LOGOUT' }); |
|||
} catch (error: any) { |
|||
console.error('[authService] handleLogout error', error); |
|||
dispatch({ |
|||
type: 'LOGIN_FAILURE', |
|||
payload: { error: error.message || AUTH_CONSTANTS.MESSAGES.UNKNOWN_ERROR } |
|||
}); |
|||
throw error; |
|||
} |
|||
}, |
|||
|
|||
// 获取当前用户信息
|
|||
async getCurrentUser(): Promise<OperationResult<LoginResponse>> { |
|||
handleRefreshToken: async (dispatch: React.Dispatch<AuthAction>) => { |
|||
try { |
|||
const response = await httpClient.get<LoginResponse>('/Users/CurrentUser'); |
|||
return response; |
|||
const refreshToken = storageService.getRefreshToken(); |
|||
console.log('[authService] handleRefreshToken start', { refreshToken }); |
|||
if (!refreshToken) { |
|||
throw new AuthError(AUTH_CONSTANTS.MESSAGES.TOKEN_EXPIRED); |
|||
} |
|||
const result = await apiService.refreshToken(refreshToken); |
|||
console.log('[authService] refreshToken result', result); |
|||
if (!result.success || !result.data) { |
|||
throw new AuthError(result.message || AUTH_CONSTANTS.MESSAGES.TOKEN_REFRESH_FAILED); |
|||
} |
|||
const { accessToken, refreshToken: newRefreshToken, user } = result.data; |
|||
const expiryTime = Date.now() + AUTH_CONSTANTS.AUTH_CONFIG.TOKEN_EXPIRY_TIME; |
|||
storageService.setAccessToken(accessToken); |
|||
storageService.setRefreshToken(newRefreshToken); |
|||
storageService.setTokenExpiry(expiryTime); |
|||
console.log('[authService] tokens refreshed', { accessToken, newRefreshToken, expiryTime }); |
|||
dispatch({ |
|||
type: 'SET_USER', |
|||
payload: { user, accessToken, refreshToken: newRefreshToken } |
|||
}); |
|||
} catch (error: any) { |
|||
return { |
|||
successMessage: null, |
|||
errorMessages: error.errorMessages || ['获取用户信息失败'], |
|||
data: null, |
|||
isSuccess: false, |
|||
}; |
|||
console.error('[authService] handleRefreshToken error', error); |
|||
dispatch({ |
|||
type: 'LOGIN_FAILURE', |
|||
payload: { error: error.message || AUTH_CONSTANTS.MESSAGES.UNKNOWN_ERROR } |
|||
}); |
|||
throw error; |
|||
} |
|||
}, |
|||
|
|||
initializeAuth: async (dispatch: React.Dispatch<AuthAction>) => { |
|||
try { |
|||
console.log('[authService] 开始初始化认证'); |
|||
dispatch({ type: 'LOGIN_START' }); |
|||
|
|||
const accessToken = storageService.getAccessToken(); |
|||
const refreshToken = storageService.getRefreshToken(); |
|||
const expiry = storageService.getTokenExpiry(); |
|||
console.log('[authService] initializeAuth - 初始状态', { |
|||
accessToken: accessToken ? '存在' : '不存在', |
|||
refreshToken: refreshToken ? '存在' : '不存在', |
|||
expiry, |
|||
currentTime: Date.now(), |
|||
isExpired: authService.isTokenExpired() |
|||
}); |
|||
|
|||
if (!accessToken || authService.isTokenExpired()) { |
|||
console.log('[authService] token 缺失或过期,尝试刷新'); |
|||
if (!refreshToken) { |
|||
console.log('[authService] 没有刷新令牌,需要重新登录'); |
|||
dispatch({ |
|||
type: 'LOGIN_FAILURE', |
|||
payload: { error: AUTH_CONSTANTS.MESSAGES.TOKEN_EXPIRED } |
|||
}); |
|||
return; |
|||
} |
|||
await authService.handleRefreshToken(dispatch); |
|||
return; |
|||
} |
|||
|
|||
console.log('[authService] 开始获取当前用户信息'); |
|||
const result = await apiService.getCurrentUser(); |
|||
console.log('[authService] getCurrentUser 结果', { |
|||
success: result.success, |
|||
message: result.message, |
|||
hasData: !!result.data, |
|||
data: result.data |
|||
}); |
|||
|
|||
if (!result.success) { |
|||
console.error('[authService] 获取用户信息失败', result.message); |
|||
throw new AuthError(result.message || AUTH_CONSTANTS.MESSAGES.USER_FETCH_FAILED); |
|||
} |
|||
|
|||
if (!result.data) { |
|||
console.error('[authService] 用户数据为空'); |
|||
throw new AuthError(AUTH_CONSTANTS.MESSAGES.USER_FETCH_FAILED); |
|||
} |
|||
|
|||
console.log('[authService] 设置用户信息到状态'); |
|||
dispatch({ |
|||
type: 'LOGIN_SUCCESS', |
|||
payload: { |
|||
user: result.data, |
|||
accessToken, |
|||
refreshToken: storageService.getRefreshToken() || '', |
|||
rememberMe: storageService.getRememberMe() |
|||
} |
|||
}); |
|||
} catch (error: any) { |
|||
console.error('[authService] initializeAuth 错误', error); |
|||
dispatch({ |
|||
type: 'LOGIN_FAILURE', |
|||
payload: { error: error.message || AUTH_CONSTANTS.MESSAGES.UNKNOWN_ERROR } |
|||
}); |
|||
throw error; |
|||
} |
|||
} |
|||
}; |
@ -0,0 +1,88 @@ |
|||
import axios, { AxiosInstance, InternalAxiosRequestConfig, AxiosResponse } from 'axios'; |
|||
import { authService } from './authService'; |
|||
|
|||
const TOKEN_EXPIRY_KEY = 'tokenExpiry'; |
|||
const TOKEN_REFRESH_THRESHOLD = 5 * 60 * 1000; // 5分钟
|
|||
|
|||
class AxiosConfig { |
|||
private instance: AxiosInstance; |
|||
|
|||
constructor() { |
|||
this.instance = axios.create({ |
|||
baseURL: process.env.REACT_APP_API_URL, |
|||
timeout: 10000, |
|||
headers: { |
|||
'Content-Type': 'application/json', |
|||
}, |
|||
}); |
|||
|
|||
this.setupInterceptors(); |
|||
} |
|||
|
|||
private setupInterceptors() { |
|||
// 请求拦截器
|
|||
this.instance.interceptors.request.use( |
|||
async (config: InternalAxiosRequestConfig) => { |
|||
const token = localStorage.getItem('accessToken'); |
|||
if (token) { |
|||
// 检查token是否即将过期
|
|||
const expiry = localStorage.getItem(TOKEN_EXPIRY_KEY); |
|||
if (expiry) { |
|||
const expiryTime = parseInt(expiry); |
|||
const currentTime = new Date().getTime(); |
|||
if (expiryTime - currentTime < TOKEN_REFRESH_THRESHOLD) { |
|||
try { |
|||
await authService.refreshToken(localStorage.getItem('refreshToken') || ''); |
|||
} catch (error) { |
|||
// 刷新失败,清除token
|
|||
localStorage.removeItem('accessToken'); |
|||
localStorage.removeItem('refreshToken'); |
|||
localStorage.removeItem(TOKEN_EXPIRY_KEY); |
|||
window.location.href = '/login'; |
|||
} |
|||
} |
|||
} |
|||
config.headers.Authorization = `Bearer ${localStorage.getItem('accessToken')}`; |
|||
} |
|||
return config; |
|||
}, |
|||
(error) => { |
|||
return Promise.reject(error); |
|||
} |
|||
); |
|||
|
|||
// 响应拦截器
|
|||
this.instance.interceptors.response.use( |
|||
(response: AxiosResponse) => { |
|||
return response; |
|||
}, |
|||
async (error) => { |
|||
if (error.response?.status === 401) { |
|||
// token过期,尝试刷新
|
|||
try { |
|||
const refreshToken = localStorage.getItem('refreshToken'); |
|||
if (refreshToken) { |
|||
await authService.refreshToken(refreshToken); |
|||
// 重试原请求
|
|||
const config = error.config; |
|||
return this.instance(config); |
|||
} |
|||
} catch (refreshError) { |
|||
// 刷新失败,清除token并跳转到登录页
|
|||
localStorage.removeItem('accessToken'); |
|||
localStorage.removeItem('refreshToken'); |
|||
localStorage.removeItem(TOKEN_EXPIRY_KEY); |
|||
window.location.href = '/login'; |
|||
} |
|||
} |
|||
return Promise.reject(error); |
|||
} |
|||
); |
|||
} |
|||
|
|||
public getInstance(): AxiosInstance { |
|||
return this.instance; |
|||
} |
|||
} |
|||
|
|||
export const axiosInstance = new AxiosConfig().getInstance(); |
@ -0,0 +1,206 @@ |
|||
import { AUTH_CONSTANTS } from '@/constants/auth'; |
|||
|
|||
export interface StorageService { |
|||
// Token 相关
|
|||
setAccessToken: (token: string) => void; |
|||
getAccessToken: () => string | null; |
|||
removeAccessToken: () => void; |
|||
|
|||
setRefreshToken: (token: string) => void; |
|||
getRefreshToken: () => string | null; |
|||
removeRefreshToken: () => void; |
|||
|
|||
// Token 过期时间
|
|||
setTokenExpiry: (expiryTime: number) => void; |
|||
getTokenExpiry: () => string | null; |
|||
removeTokenExpiry: () => void; |
|||
|
|||
// 记住登录状态
|
|||
setRememberMe: (value: boolean) => void; |
|||
getRememberMe: () => boolean; |
|||
removeRememberMe: () => void; |
|||
|
|||
// 登录尝试次数
|
|||
setLoginAttempts: (attempts: number) => void; |
|||
getLoginAttempts: () => number; |
|||
removeLoginAttempts: () => void; |
|||
|
|||
// 最后登录尝试时间
|
|||
setLastLoginAttempt: (timestamp: number) => void; |
|||
getLastLoginAttempt: () => number; |
|||
removeLastLoginAttempt: () => void; |
|||
|
|||
// 清除所有认证相关存储
|
|||
clearAuth: () => void; |
|||
} |
|||
|
|||
class StorageError extends Error { |
|||
constructor(message: string) { |
|||
super(message); |
|||
this.name = 'StorageError'; |
|||
} |
|||
} |
|||
|
|||
export const storageService: StorageService = { |
|||
// Token 相关
|
|||
setAccessToken: (token: string) => { |
|||
try { |
|||
localStorage.setItem(AUTH_CONSTANTS.STORAGE_KEYS.ACCESS_TOKEN, token); |
|||
} catch (error) { |
|||
throw new StorageError('设置访问令牌失败'); |
|||
} |
|||
}, |
|||
|
|||
getAccessToken: () => { |
|||
try { |
|||
return localStorage.getItem(AUTH_CONSTANTS.STORAGE_KEYS.ACCESS_TOKEN); |
|||
} catch (error) { |
|||
throw new StorageError('获取访问令牌失败'); |
|||
} |
|||
}, |
|||
|
|||
removeAccessToken: () => { |
|||
try { |
|||
localStorage.removeItem(AUTH_CONSTANTS.STORAGE_KEYS.ACCESS_TOKEN); |
|||
} catch (error) { |
|||
throw new StorageError('移除访问令牌失败'); |
|||
} |
|||
}, |
|||
|
|||
setRefreshToken: (token: string) => { |
|||
try { |
|||
localStorage.setItem(AUTH_CONSTANTS.STORAGE_KEYS.REFRESH_TOKEN, token); |
|||
} catch (error) { |
|||
throw new StorageError('设置刷新令牌失败'); |
|||
} |
|||
}, |
|||
|
|||
getRefreshToken: () => { |
|||
try { |
|||
return localStorage.getItem(AUTH_CONSTANTS.STORAGE_KEYS.REFRESH_TOKEN); |
|||
} catch (error) { |
|||
throw new StorageError('获取刷新令牌失败'); |
|||
} |
|||
}, |
|||
|
|||
removeRefreshToken: () => { |
|||
try { |
|||
localStorage.removeItem(AUTH_CONSTANTS.STORAGE_KEYS.REFRESH_TOKEN); |
|||
} catch (error) { |
|||
throw new StorageError('移除刷新令牌失败'); |
|||
} |
|||
}, |
|||
|
|||
// Token 过期时间
|
|||
setTokenExpiry: (expiryTime: number) => { |
|||
try { |
|||
localStorage.setItem(AUTH_CONSTANTS.STORAGE_KEYS.TOKEN_EXPIRY, expiryTime.toString()); |
|||
} catch (error) { |
|||
throw new StorageError('设置令牌过期时间失败'); |
|||
} |
|||
}, |
|||
|
|||
getTokenExpiry: () => { |
|||
try { |
|||
return localStorage.getItem(AUTH_CONSTANTS.STORAGE_KEYS.TOKEN_EXPIRY); |
|||
} catch (error) { |
|||
throw new StorageError('获取令牌过期时间失败'); |
|||
} |
|||
}, |
|||
|
|||
removeTokenExpiry: () => { |
|||
try { |
|||
localStorage.removeItem(AUTH_CONSTANTS.STORAGE_KEYS.TOKEN_EXPIRY); |
|||
} catch (error) { |
|||
throw new StorageError('移除令牌过期时间失败'); |
|||
} |
|||
}, |
|||
|
|||
// 记住登录状态
|
|||
setRememberMe: (value: boolean) => { |
|||
try { |
|||
localStorage.setItem(AUTH_CONSTANTS.STORAGE_KEYS.REMEMBER_ME, value.toString()); |
|||
} catch (error) { |
|||
throw new StorageError('设置记住登录状态失败'); |
|||
} |
|||
}, |
|||
|
|||
getRememberMe: () => { |
|||
try { |
|||
return localStorage.getItem(AUTH_CONSTANTS.STORAGE_KEYS.REMEMBER_ME) === 'true'; |
|||
} catch (error) { |
|||
throw new StorageError('获取记住登录状态失败'); |
|||
} |
|||
}, |
|||
|
|||
removeRememberMe: () => { |
|||
try { |
|||
localStorage.removeItem(AUTH_CONSTANTS.STORAGE_KEYS.REMEMBER_ME); |
|||
} catch (error) { |
|||
throw new StorageError('移除记住登录状态失败'); |
|||
} |
|||
}, |
|||
|
|||
// 登录尝试次数
|
|||
setLoginAttempts: (attempts: number) => { |
|||
try { |
|||
localStorage.setItem(AUTH_CONSTANTS.STORAGE_KEYS.LOGIN_ATTEMPTS, attempts.toString()); |
|||
} catch (error) { |
|||
throw new StorageError('设置登录尝试次数失败'); |
|||
} |
|||
}, |
|||
|
|||
getLoginAttempts: () => { |
|||
try { |
|||
const attempts = localStorage.getItem(AUTH_CONSTANTS.STORAGE_KEYS.LOGIN_ATTEMPTS); |
|||
return attempts ? parseInt(attempts) : 0; |
|||
} catch (error) { |
|||
throw new StorageError('获取登录尝试次数失败'); |
|||
} |
|||
}, |
|||
|
|||
removeLoginAttempts: () => { |
|||
try { |
|||
localStorage.removeItem(AUTH_CONSTANTS.STORAGE_KEYS.LOGIN_ATTEMPTS); |
|||
} catch (error) { |
|||
throw new StorageError('移除登录尝试次数失败'); |
|||
} |
|||
}, |
|||
|
|||
// 最后登录尝试时间
|
|||
setLastLoginAttempt: (timestamp: number) => { |
|||
try { |
|||
localStorage.setItem(AUTH_CONSTANTS.STORAGE_KEYS.LAST_LOGIN_ATTEMPT, timestamp.toString()); |
|||
} catch (error) { |
|||
throw new StorageError('设置最后登录尝试时间失败'); |
|||
} |
|||
}, |
|||
|
|||
getLastLoginAttempt: () => { |
|||
try { |
|||
const timestamp = localStorage.getItem(AUTH_CONSTANTS.STORAGE_KEYS.LAST_LOGIN_ATTEMPT); |
|||
return timestamp ? parseInt(timestamp) : 0; |
|||
} catch (error) { |
|||
throw new StorageError('获取最后登录尝试时间失败'); |
|||
} |
|||
}, |
|||
|
|||
removeLastLoginAttempt: () => { |
|||
try { |
|||
localStorage.removeItem(AUTH_CONSTANTS.STORAGE_KEYS.LAST_LOGIN_ATTEMPT); |
|||
} catch (error) { |
|||
throw new StorageError('移除最后登录尝试时间失败'); |
|||
} |
|||
}, |
|||
|
|||
// 清除所有认证相关存储
|
|||
clearAuth: () => { |
|||
try { |
|||
Object.values(AUTH_CONSTANTS.STORAGE_KEYS).forEach(key => { |
|||
localStorage.removeItem(key); |
|||
}); |
|||
} catch (error) { |
|||
throw new StorageError('清除认证存储失败'); |
|||
} |
|||
} |
|||
}; |
@ -0,0 +1,19 @@ |
|||
interface User { |
|||
userId?: string; |
|||
userName?: string; |
|||
email?: string; |
|||
phoneNumber?: string; |
|||
} |
|||
|
|||
export function getUserInfo(user: User | { user?: User } | null) { |
|||
let realUser: User | undefined; |
|||
if (user && typeof user === 'object' && 'user' in user) { |
|||
realUser = user.user; |
|||
} else { |
|||
realUser = user as User | undefined; |
|||
} |
|||
return { |
|||
userName: realUser?.userName || '未登录', |
|||
email: realUser?.email || '' |
|||
}; |
|||
} |
Loading…
Reference in new issue