fix(web): align auth contract with api

This commit is contained in:
Xiaoxia AI
2026-06-22 07:12:53 +08:00
parent 45f15c1866
commit 02d8000202
4 changed files with 59 additions and 41 deletions
+37 -4
View File
@@ -11,9 +11,13 @@ export interface LoginRequest {
export interface LoginResponse {
access_token: string;
refresh_token: string;
refresh_token?: string | null;
token_type: string;
expires_in: number;
user_id: string;
email: string;
username: string;
display_name: string;
}
export interface RegisterRequest {
@@ -25,13 +29,42 @@ export interface RegisterRequest {
export interface User {
id: string;
user_id: string;
email: string;
username: string;
display_name: string;
is_email_verified: boolean;
created_at: string;
email_verified: boolean;
created_at?: string;
}
interface UserResponse {
id?: string;
user_id?: string;
email: string;
username: string;
display_name: string;
is_email_verified?: boolean;
email_verified?: boolean;
created_at?: string;
}
const normalizeUser = (data: UserResponse): User => {
const userId = data.id ?? data.user_id ?? '';
const emailVerified = data.is_email_verified ?? data.email_verified ?? false;
return {
id: userId,
user_id: userId,
email: data.email,
username: data.username,
display_name: data.display_name,
is_email_verified: emailVerified,
email_verified: emailVerified,
created_at: data.created_at,
};
};
// 登录
export const login = async (data: LoginRequest): Promise<LoginResponse> => {
const response = await apiClient.post('/auth/login', data);
@@ -51,8 +84,8 @@ export const logout = async (): Promise<void> => {
// 获取当前用户
export const getCurrentUser = async (): Promise<User> => {
const response = await apiClient.get('/auth/me');
return response.data;
const response = await apiClient.get<UserResponse>('/auth/me');
return normalizeUser(response.data);
};
// 请求密码重置
+4 -32
View File
@@ -27,41 +27,13 @@ apiClient.interceptors.request.use(
}
);
// 响应拦截器:处理错误和 Token 刷新
// 响应拦截器:处理未授权状态
apiClient.interceptors.response.use(
(response) => response,
async (error: AxiosError) => {
const originalRequest = error.config;
// Token 过期,尝试刷新
if (error.response?.status === 401 && originalRequest) {
const refreshToken = localStorage.getItem('refresh_token');
if (refreshToken) {
try {
const { data } = await axios.post('/api/v1/auth/refresh', {
refresh_token: refreshToken,
});
// 保存新 Token
localStorage.setItem('access_token', data.access_token);
// 重试原请求
if (originalRequest.headers) {
originalRequest.headers.Authorization = `Bearer ${data.access_token}`;
}
return apiClient(originalRequest);
} catch (refreshError) {
// 刷新失败,清除 Token 并跳转登录
localStorage.removeItem('access_token');
localStorage.removeItem('refresh_token');
window.location.href = '/login';
return Promise.reject(refreshError);
}
} else {
// 没有 refresh token,直接跳转登录
window.location.href = '/login';
}
if (error.response?.status === 401) {
localStorage.removeItem('access_token');
localStorage.removeItem('refresh_token');
}
return Promise.reject(error);
+8 -2
View File
@@ -18,13 +18,19 @@ export const useLogin = () => {
// 手动处理成功后的逻辑
const login = async (credentials: Parameters<typeof authApi.login>[0]) => {
const data = await mutation.mutateAsync(credentials);
const refreshToken = data.refresh_token ?? null;
// 先保存 token
localStorage.setItem('access_token', data.access_token);
localStorage.setItem('refresh_token', data.refresh_token);
if (refreshToken) {
localStorage.setItem('refresh_token', refreshToken);
} else {
localStorage.removeItem('refresh_token');
}
// 获取用户信息
const user = await authApi.getCurrentUser();
setAuth(user, data.access_token, data.refresh_token);
setAuth(user, data.access_token, refreshToken);
navigate('/workspaces');
return data;
};
+10 -3
View File
@@ -7,10 +7,12 @@ import { persist } from 'zustand/middleware';
interface User {
id: string;
user_id: string;
email: string;
username: string;
display_name: string;
is_email_verified: boolean;
email_verified: boolean;
}
interface AuthState {
@@ -20,7 +22,8 @@ interface AuthState {
isAuthenticated: boolean;
// Actions
setAuth: (user: User, accessToken: string, refreshToken: string) => void;
setAuth: (user: User, accessToken: string, refreshToken?: string | null) => void;
clearAuth: () => void;
setUser: (user: User) => void;
}
@@ -33,9 +36,13 @@ export const useAuthStore = create<AuthState>()(
refreshToken: null,
isAuthenticated: false,
setAuth: (user, accessToken, refreshToken) => {
setAuth: (user, accessToken, refreshToken = null) => {
localStorage.setItem('access_token', accessToken);
localStorage.setItem('refresh_token', refreshToken);
if (refreshToken) {
localStorage.setItem('refresh_token', refreshToken);
} else {
localStorage.removeItem('refresh_token');
}
set({
user,
accessToken,