feat: 前端认证网关 + API 自动附加 JWT
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
- AuthProvider 管理 jumpToken 交换和 JWT 生命周期 - 未授权页面(ShieldX 图标 + 提示文字) - 加载中旋转动画 - fetchJson 全局客户端自动附加 Authorization header - 401 响应触发重新认证 - JWT 存 sessionStorage,刷新不丢失 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
30
src/App.tsx
30
src/App.tsx
@@ -2,12 +2,40 @@ import { Truck, Route } from 'lucide-react';
|
||||
import { Shell, type ModuleConfig } from './components/Shell';
|
||||
import AssetsModule from './modules/assets/AssetsModule';
|
||||
import MileageModule from './modules/mileage/MileageModule';
|
||||
import AuthProvider from './auth/AuthProvider';
|
||||
import { useAuth } from './auth/useAuth';
|
||||
import UnauthorizedPage from './auth/UnauthorizedPage';
|
||||
|
||||
const MODULES: ModuleConfig[] = [
|
||||
{ id: 'assets', label: '资产管理', icon: Truck, component: AssetsModule },
|
||||
{ id: 'mileage', label: '里程管理', icon: Route, component: MileageModule },
|
||||
];
|
||||
|
||||
export default function App() {
|
||||
function AuthGate() {
|
||||
const { isLoading, isAuthenticated, error } = useAuth();
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className="min-h-screen bg-[#F8F9FB] flex items-center justify-center">
|
||||
<div className="text-center">
|
||||
<div className="w-8 h-8 border-2 border-blue-600 border-t-transparent rounded-full animate-spin mx-auto mb-3"></div>
|
||||
<p className="text-xs text-slate-400 font-bold">正在验证身份...</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (!isAuthenticated) {
|
||||
return <UnauthorizedPage message={error || undefined} />;
|
||||
}
|
||||
|
||||
return <Shell modules={MODULES} />;
|
||||
}
|
||||
|
||||
export default function App() {
|
||||
return (
|
||||
<AuthProvider>
|
||||
<AuthGate />
|
||||
</AuthProvider>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user