refactor(auth): standardize authorization token handling
- Replace 'token' with 'Authorization' in localStorage keys for consistency - Update auth guard, request interceptor and login hooks to use new key - Add updateAuthorization method to auth hook for better state management
This commit is contained in:
@@ -11,8 +11,8 @@ const AuthGuard: React.FC<AuthGuardProps> = ({ children }) => {
|
|||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
// 直接从localStorage检查token,避免React状态更新的延迟
|
// 直接从localStorage检查token,避免React状态更新的延迟
|
||||||
const token = localStorage.getItem('token');
|
const authorization = localStorage.getItem('Authorization');
|
||||||
const isAuthenticated = !!token;
|
const isAuthenticated = !!authorization;
|
||||||
const isLoginPage = location.pathname === '/login';
|
const isLoginPage = location.pathname === '/login';
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import { rsaPsw } from '../utils/encryption';
|
|||||||
export const useOAuthCallback = () => {
|
export const useOAuthCallback = () => {
|
||||||
const [searchParams, setSearchParams] = useSearchParams();
|
const [searchParams, setSearchParams] = useSearchParams();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const error = searchParams.get('error');
|
const error = searchParams.get('error');
|
||||||
const newSearchParams: URLSearchParams = useMemo(
|
const newSearchParams: URLSearchParams = useMemo(
|
||||||
() => new URLSearchParams(searchParams.toString()),
|
() => new URLSearchParams(searchParams.toString()),
|
||||||
@@ -33,7 +33,7 @@ export const useOAuthCallback = () => {
|
|||||||
const auth = searchParams.get('auth');
|
const auth = searchParams.get('auth');
|
||||||
if (auth) {
|
if (auth) {
|
||||||
// 存储认证信息
|
// 存储认证信息
|
||||||
localStorage.setItem('token', auth);
|
localStorage.setItem('Authorization', auth);
|
||||||
newSearchParams.delete('auth');
|
newSearchParams.delete('auth');
|
||||||
setSearchParams(newSearchParams);
|
setSearchParams(newSearchParams);
|
||||||
navigate('/');
|
navigate('/');
|
||||||
@@ -56,36 +56,40 @@ export const useAuth = () => {
|
|||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const [searchParams] = useSearchParams();
|
const [searchParams] = useSearchParams();
|
||||||
const [isAuthenticated, setIsAuthenticated] = useState<boolean | null>(null);
|
|
||||||
const [userInfo, setUserInfo] = useState<any>(null);
|
const [userInfo, setUserInfo] = useState<any>(null);
|
||||||
const [token, setToken] = useState<string | null>(null);
|
const [token, setToken] = useState<string | null>(null);
|
||||||
|
const [authorization, setAuthorization] = useState<string | null>(null);
|
||||||
|
|
||||||
const [isLoading, setIsLoading] = useState(true);
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
|
|
||||||
// OAuth回调处理
|
// OAuth回调处理
|
||||||
const auth = useOAuthCallback();
|
const auth = useOAuthCallback();
|
||||||
|
|
||||||
|
const isAuthenticated = useMemo(() => authorization !== null && authorization !== '', [authorization]);
|
||||||
|
|
||||||
// 检查认证状态
|
// 检查认证状态
|
||||||
const checkAuthStatus = () => {
|
const checkAuthStatus = () => {
|
||||||
try {
|
try {
|
||||||
const storedToken = localStorage.getItem('token');
|
const storedToken = localStorage.getItem('token');
|
||||||
|
const storedAuthorization = localStorage.getItem('Authorization');
|
||||||
const storedUserInfo = localStorage.getItem('userInfo');
|
const storedUserInfo = localStorage.getItem('userInfo');
|
||||||
|
|
||||||
if (storedToken) {
|
if (storedAuthorization) {
|
||||||
setToken(storedToken);
|
setToken(storedToken);
|
||||||
setIsAuthenticated(true);
|
setAuthorization(storedAuthorization);
|
||||||
|
|
||||||
if (storedUserInfo) {
|
if (storedUserInfo) {
|
||||||
setUserInfo(JSON.parse(storedUserInfo));
|
setUserInfo(JSON.parse(storedUserInfo));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
setToken(null);
|
setToken(null);
|
||||||
setIsAuthenticated(false);
|
setAuthorization(null);
|
||||||
setUserInfo(null);
|
setUserInfo(null);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error checking auth status:', error);
|
console.error('Error checking auth status:', error);
|
||||||
setToken(null);
|
setToken(null);
|
||||||
setIsAuthenticated(false);
|
setAuthorization(null);
|
||||||
setUserInfo(null);
|
setUserInfo(null);
|
||||||
} finally {
|
} finally {
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
@@ -97,16 +101,19 @@ export const useAuth = () => {
|
|||||||
localStorage.removeItem('token');
|
localStorage.removeItem('token');
|
||||||
localStorage.removeItem('userInfo');
|
localStorage.removeItem('userInfo');
|
||||||
setToken(null);
|
setToken(null);
|
||||||
setIsAuthenticated(false);
|
|
||||||
setUserInfo(null);
|
setUserInfo(null);
|
||||||
navigate('/login');
|
navigate('/login');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const updateAuthorization = (newAuthorization: string) => {
|
||||||
|
setAuthorization(newAuthorization);
|
||||||
|
localStorage.setItem('Authorization', newAuthorization);
|
||||||
|
};
|
||||||
|
|
||||||
// 更新认证状态
|
// 更新认证状态
|
||||||
const updateAuthStatus = (newToken: string, newUserInfo: any) => {
|
const updateAuthStatus = (newToken: string, newUserInfo: any) => {
|
||||||
setToken(newToken);
|
setToken(newToken);
|
||||||
setUserInfo(newUserInfo);
|
setUserInfo(newUserInfo);
|
||||||
setIsAuthenticated(true);
|
|
||||||
localStorage.setItem('token', newToken);
|
localStorage.setItem('token', newToken);
|
||||||
localStorage.setItem('userInfo', JSON.stringify(newUserInfo));
|
localStorage.setItem('userInfo', JSON.stringify(newUserInfo));
|
||||||
};
|
};
|
||||||
@@ -142,6 +149,7 @@ export const useAuth = () => {
|
|||||||
isLoading,
|
isLoading,
|
||||||
checkAuthStatus,
|
checkAuthStatus,
|
||||||
logout,
|
logout,
|
||||||
|
updateAuthorization,
|
||||||
updateAuthStatus,
|
updateAuthStatus,
|
||||||
redirectToLogin,
|
redirectToLogin,
|
||||||
redirectAfterLogin,
|
redirectAfterLogin,
|
||||||
@@ -171,33 +179,37 @@ export const useLogin = () => {
|
|||||||
|
|
||||||
const login = async (data: LoginFormData) => {
|
const login = async (data: LoginFormData) => {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// RSA加密密码
|
// RSA加密密码
|
||||||
const encryptedPassword = rsaPsw(data.password);
|
const encryptedPassword = rsaPsw(data.password);
|
||||||
const response = await userService.login({
|
const response = await userService.login({
|
||||||
email: data.email.trim(),
|
email: data.email.trim(),
|
||||||
password: encryptedPassword
|
password: encryptedPassword
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data: res = {} } = response;
|
const { data: res = {}, headers } = response;
|
||||||
|
|
||||||
|
const authorization: string = headers['authorization'] ?? headers['Authorization'] ?? '';
|
||||||
|
|
||||||
|
localStorage.setItem('Authorization', authorization);
|
||||||
const { code, message } = res;
|
const { code, message } = res;
|
||||||
|
|
||||||
if (code === 0) {
|
if (code === 0) {
|
||||||
// 登录成功,处理token和用户信息
|
// 登录成功,处理token和用户信息
|
||||||
const { data: userData } = res;
|
const { data: userData } = res;
|
||||||
const token = userData.access_token;
|
const token: string = userData.access_token;
|
||||||
const userInfo = {
|
const userInfo = {
|
||||||
...userData,
|
...userData,
|
||||||
avatar: userData.avatar,
|
avatar: userData.avatar,
|
||||||
name: userData.nickname,
|
name: userData.nickname,
|
||||||
email: userData.email,
|
email: userData.email,
|
||||||
};
|
};
|
||||||
|
|
||||||
// 同步更新localStorage
|
// 同步更新localStorage
|
||||||
localStorage.setItem('token', token);
|
localStorage.setItem('token', token);
|
||||||
localStorage.setItem('userInfo', JSON.stringify(userInfo));
|
localStorage.setItem('userInfo', JSON.stringify(userInfo));
|
||||||
|
|
||||||
// 直接进行重定向,不依赖React状态更新
|
// 直接进行重定向,不依赖React状态更新
|
||||||
const redirectUrl = searchParams.get('redirect');
|
const redirectUrl = searchParams.get('redirect');
|
||||||
if (redirectUrl) {
|
if (redirectUrl) {
|
||||||
@@ -205,20 +217,20 @@ export const useLogin = () => {
|
|||||||
} else {
|
} else {
|
||||||
navigate('/', { replace: true });
|
navigate('/', { replace: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
return { success: true };
|
return { success: true };
|
||||||
} else {
|
} else {
|
||||||
// 登录失败
|
// 登录失败
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
error: message || t('login.loginFailed')
|
error: message || t('login.loginFailed')
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
// 处理网络错误或其他异常
|
// 处理网络错误或其他异常
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
error: error.message || t('login.networkError')
|
error: error.message || t('login.networkError')
|
||||||
};
|
};
|
||||||
} finally {
|
} finally {
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
@@ -237,11 +249,11 @@ export const useRegister = () => {
|
|||||||
|
|
||||||
const register = async (data: RegisterFormData) => {
|
const register = async (data: RegisterFormData) => {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// RSA加密密码
|
// RSA加密密码
|
||||||
const encryptedPassword = rsaPsw(data.password);
|
const encryptedPassword = rsaPsw(data.password);
|
||||||
|
|
||||||
const response = await userService.register({
|
const response = await userService.register({
|
||||||
nickname: data.nickname,
|
nickname: data.nickname,
|
||||||
email: data.email.trim(),
|
email: data.email.trim(),
|
||||||
@@ -250,25 +262,25 @@ export const useRegister = () => {
|
|||||||
|
|
||||||
const { data: res = {} } = response;
|
const { data: res = {} } = response;
|
||||||
const { code, message } = res;
|
const { code, message } = res;
|
||||||
|
|
||||||
if (code === 0) {
|
if (code === 0) {
|
||||||
// 注册成功
|
// 注册成功
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
email: data.email
|
email: data.email
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
// 注册失败
|
// 注册失败
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
error: message || t('login.registerFailed')
|
error: message || t('login.registerFailed')
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
// 处理网络错误或其他异常
|
// 处理网络错误或其他异常
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
error: error.message || t('login.networkError')
|
error: error.message || t('login.networkError')
|
||||||
};
|
};
|
||||||
} finally {
|
} finally {
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
@@ -335,23 +347,23 @@ export const useLoginForm = () => {
|
|||||||
error,
|
error,
|
||||||
loginForm,
|
loginForm,
|
||||||
registerForm,
|
registerForm,
|
||||||
|
|
||||||
// 表单操作
|
// 表单操作
|
||||||
handleTabChange,
|
handleTabChange,
|
||||||
switchToLogin,
|
switchToLogin,
|
||||||
setFormError,
|
setFormError,
|
||||||
clearError,
|
clearError,
|
||||||
|
|
||||||
// 表单验证规则
|
// 表单验证规则
|
||||||
loginValidation: {
|
loginValidation: {
|
||||||
email: {
|
email: {
|
||||||
required: t('login.emailPlaceholder'),
|
required: t('login.emailPlaceholder'),
|
||||||
pattern: {
|
pattern: {
|
||||||
value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
|
value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
|
||||||
message: t('login.emailInvalid')
|
message: t('login.emailInvalid')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
password: {
|
password: {
|
||||||
required: t('login.passwordPlaceholder'),
|
required: t('login.passwordPlaceholder'),
|
||||||
minLength: {
|
minLength: {
|
||||||
value: 6,
|
value: 6,
|
||||||
@@ -360,21 +372,21 @@ export const useLoginForm = () => {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
registerValidation: {
|
registerValidation: {
|
||||||
nickname: {
|
nickname: {
|
||||||
required: t('login.nicknamePlaceholder'),
|
required: t('login.nicknamePlaceholder'),
|
||||||
minLength: {
|
minLength: {
|
||||||
value: 2,
|
value: 2,
|
||||||
message: t('login.nicknameMinLength')
|
message: t('login.nicknameMinLength')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
email: {
|
email: {
|
||||||
required: t('login.emailPlaceholder'),
|
required: t('login.emailPlaceholder'),
|
||||||
pattern: {
|
pattern: {
|
||||||
value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
|
value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
|
||||||
message: t('login.emailInvalid')
|
message: t('login.emailInvalid')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
password: {
|
password: {
|
||||||
required: t('login.passwordPlaceholder'),
|
required: t('login.passwordPlaceholder'),
|
||||||
minLength: {
|
minLength: {
|
||||||
value: 8,
|
value: 8,
|
||||||
@@ -396,18 +408,18 @@ export const useLoginPage = () => {
|
|||||||
const handleLogin = async (data: LoginFormData) => {
|
const handleLogin = async (data: LoginFormData) => {
|
||||||
formHook.clearError();
|
formHook.clearError();
|
||||||
const result = await loginHook.login(data);
|
const result = await loginHook.login(data);
|
||||||
|
|
||||||
if (!result.success && result.error) {
|
if (!result.success && result.error) {
|
||||||
formHook.setFormError(result.error);
|
formHook.setFormError(result.error);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleRegister = async (data: RegisterFormData) => {
|
const handleRegister = async (data: RegisterFormData) => {
|
||||||
formHook.clearError();
|
formHook.clearError();
|
||||||
const result = await registerHook.register(data);
|
const result = await registerHook.register(data);
|
||||||
|
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
// 注册成功,切换到登录表单并填入邮箱
|
// 注册成功,切换到登录表单并填入邮箱
|
||||||
formHook.registerForm.reset();
|
formHook.registerForm.reset();
|
||||||
@@ -415,7 +427,7 @@ export const useLoginPage = () => {
|
|||||||
} else if (result.error) {
|
} else if (result.error) {
|
||||||
formHook.setFormError(result.error);
|
formHook.setFormError(result.error);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -424,7 +436,7 @@ export const useLoginPage = () => {
|
|||||||
return {
|
return {
|
||||||
// 表单相关
|
// 表单相关
|
||||||
...formHook,
|
...formHook,
|
||||||
|
|
||||||
// 提交处理
|
// 提交处理
|
||||||
handleLogin,
|
handleLogin,
|
||||||
handleRegister,
|
handleRegister,
|
||||||
|
|||||||
@@ -47,12 +47,12 @@ export type ResultCode =
|
|||||||
|
|
||||||
// 获取授权token
|
// 获取授权token
|
||||||
const getAuthorization = (): string => {
|
const getAuthorization = (): string => {
|
||||||
return localStorage.getItem('token') || '';
|
return localStorage.getItem(Authorization) || '';
|
||||||
};
|
};
|
||||||
|
|
||||||
// 重定向到登录页
|
// 重定向到登录页
|
||||||
const redirectToLogin = (): void => {
|
const redirectToLogin = (): void => {
|
||||||
localStorage.removeItem('token');
|
localStorage.removeItem(Authorization);
|
||||||
window.location.href = '/login';
|
window.location.href = '/login';
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -94,9 +94,9 @@ request.interceptors.request.use(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 添加授权头
|
// 添加授权头
|
||||||
const token = getAuthorization();
|
const authorization = getAuthorization();
|
||||||
if (token && !config.headers?.skipToken) {
|
if (authorization && !config.headers?.skipToken) {
|
||||||
config.headers[Authorization] = token;
|
config.headers.Authorization = authorization;
|
||||||
}
|
}
|
||||||
|
|
||||||
return config;
|
return config;
|
||||||
|
|||||||
Reference in New Issue
Block a user