| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566 |
- import React, { useEffect, useState } from 'react';
- import { useNavigate } from 'react-router-dom';
- import { authService } from '../services/authService';
- import { Loader2 } from '../icons/commonIcons';
- interface ProtectedRouteProps {
- children: React.ReactNode;
- }
- /**
- * 路由保护组件
- * 确保只有已登录用户才能访问受保护的页面
- */
- const ProtectedRoute: React.FC<ProtectedRouteProps> = ({ children }) => {
- const navigate = useNavigate();
- const [isChecking, setIsChecking] = useState(true);
- const [isAuthenticated, setIsAuthenticated] = useState(false);
- useEffect(() => {
- const checkAuth = () => {
- const authenticated = authService.isAuthenticated();
- setIsAuthenticated(authenticated);
-
- if (!authenticated) {
- // 未登录,跳转到登录页
- navigate('/login', { replace: true });
- }
- setIsChecking(false);
- };
- // 初始检查
- checkAuth();
- // 订阅认证状态变化
- const unsubscribe = authService.subscribe(() => {
- const authenticated = authService.isAuthenticated();
- setIsAuthenticated(authenticated);
- if (!authenticated) {
- navigate('/login', { replace: true });
- }
- });
- return () => {
- unsubscribe();
- };
- }, [navigate]);
- if (isChecking) {
- return (
- <div className="min-h-screen bg-gray-50 flex items-center justify-center">
- <div className="flex items-center gap-3">
- <Loader2 className="w-6 h-6 text-blue-600 animate-spin" />
- <span className="text-gray-600">验证登录状态...</span>
- </div>
- </div>
- );
- }
- if (!isAuthenticated) {
- return null;
- }
- return <>{children}</>;
- };
- export default ProtectedRoute;
|