feat(auth): 实现登录注册功能并重构 App 组件
- 新增登录和注册页面组件
- 实现用户认证和权限管理逻辑
- 重构 App 组件,使用 Router 和 AuthProvider
- 添加管理员面板和论坛页面组件
Change-Id: Iaa4502616970e75e3268537f73c75dac8f60e24d
diff --git a/src/features/auth/contexts/AuthContext.jsx b/src/features/auth/contexts/AuthContext.jsx
new file mode 100644
index 0000000..5f9b37e
--- /dev/null
+++ b/src/features/auth/contexts/AuthContext.jsx
@@ -0,0 +1,133 @@
+import React, { createContext, useContext, useState, useEffect, useCallback } from 'react';
+import { loginUser, registerUser, getUserInfo, logoutUser } from '../services/authApi';
+import { message } from 'antd';
+import { useNavigate } from 'react-router-dom'; // 导入 useNavigate
+
+const AuthContext = createContext(null);
+
+export const AuthProvider = ({ children }) => {
+ const [user, setUser] = useState(null);
+ const [loading, setLoading] = useState(true); // 初始加载状态
+ const [isAuthenticated, setIsAuthenticated] = useState(false);
+ const navigate = useNavigate();
+
+ const loadAuthData = useCallback(() => {
+ setLoading(true);
+ try {
+ const storedToken = localStorage.getItem('authToken'); // 假设您使用token
+ const storedUser = localStorage.getItem('user');
+
+ if (storedToken && storedUser) {
+ setUser(JSON.parse(storedUser));
+ setIsAuthenticated(true);
+ // 调用API获取最新的用户信息
+ getUserInfo().then(response => {
+ if (response.data && response.data.user) {
+ setUser(response.data.user);
+ localStorage.setItem('user', JSON.stringify(response.data.user));
+ }
+ }).catch(error => {
+ console.error("获取用户信息失败", error);
+ });
+ } else {
+ setIsAuthenticated(false);
+ setUser(null);
+ }
+ } catch (error) {
+ console.error("Failed to load auth data from storage", error);
+ setIsAuthenticated(false);
+ setUser(null);
+ } finally {
+ setLoading(false);
+ }
+ }, []);
+
+ useEffect(() => {
+ loadAuthData();
+ }, [loadAuthData]);
+
+ const login = async (credentials) => {
+ setLoading(true);
+ try {
+ const response = await loginUser(credentials);
+ const { token, user: userData } = response.data;
+
+ localStorage.setItem('authToken', token);
+ localStorage.setItem('user', JSON.stringify(userData));
+ setUser(userData);
+ setIsAuthenticated(true);
+ message.success('登录成功');
+ return userData;
+ } catch (error) {
+ console.error("Login failed", error);
+ setIsAuthenticated(false);
+ setUser(null);
+ message.error(error.message || '登录失败,请检查用户名和密码');
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ const register = async (userData) => {
+ setLoading(true);
+ try {
+ const response = await registerUser(userData);
+ const { token, user: newUser } = response.data;
+
+ localStorage.setItem('authToken', token);
+ localStorage.setItem('user', JSON.stringify(newUser));
+ setUser(newUser);
+ setIsAuthenticated(true);
+ message.success('注册成功');
+ return newUser;
+ } catch (error) {
+ console.error("Registration failed", error);
+ message.error(error.message || '注册失败,请稍后再试');
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ const logout = async () => {
+ try {
+ await logoutUser();
+ localStorage.removeItem('authToken');
+ localStorage.removeItem('user');
+ localStorage.removeItem('permissions'); // 移除旧的权限存储
+ setUser(null);
+ setIsAuthenticated(false);
+ message.success('已成功退出登录');
+ navigate('/login');
+ return true;
+ } catch (error) {
+ console.error("登出失败", error);
+ message.error('登出失败');
+ return false;
+ }
+ };
+
+ const hasRole = useCallback((roleName) => {
+ return user?.role === roleName;
+ }, [user]);
+
+ const value = {
+ user,
+ isAuthenticated,
+ loading,
+ login,
+ register,
+ logout,
+ hasRole,
+ reloadAuthData: loadAuthData // 暴露一个重新加载数据的方法
+ };
+
+ return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
+};
+
+export const useAuth = () => {
+ const context = useContext(AuthContext);
+ if (context === undefined || context === null) { // 增加了对 null 的检查
+ throw new Error('useAuth must be used within an AuthProvider');
+ }
+ return context;
+};
\ No newline at end of file