Skip to content

Commit 2390d7a

Browse files
the-dev-zclaude
andauthored
fix(web): add auth guards to prevent unauthorized API calls (NoFxAiOS#934)
Add `user && token` guard to all authenticated SWR calls to prevent requests with `Authorization: Bearer null` when users refresh the page before AuthContext finishes loading the token from localStorage. ## Problem When users refresh the page: 1. React components mount immediately 2. SWR hooks fire API requests 3. AuthContext is still loading token from localStorage 4. Requests sent with `Authorization: Bearer null` 5. Backend returns 401 errors This causes: - Unnecessary 401 errors in backend logs - Error messages in browser console - Poor user experience on page refresh ## Solution Add auth check to SWR key conditions using pattern: ```typescript user && token && condition ? key : null ``` When `user` or `token` is null, SWR key becomes `null`, preventing the request. Once AuthContext loads, SWR automatically revalidates and fetches data. ## Changes **TraderDashboard.tsx** (5 auth guards added): - status: `user && token && selectedTraderId ? 'status-...' : null` - account: `user && token && selectedTraderId ? 'account-...' : null` - positions: `user && token && selectedTraderId ? 'positions-...' : null` - decisions: `user && token && selectedTraderId ? 'decisions/...' : null` - stats: `user && token && selectedTraderId ? 'statistics-...' : null` **EquityChart.tsx** (2 auth guards added + useAuth import): - Import `useAuth` from '../contexts/AuthContext' - Add `const { user, token } = useAuth()` - history: `user && token && traderId ? 'equity-history-...' : null` - account: `user && token && traderId ? 'account-...' : null` **apiGuard.test.ts** (new file, 370 lines): - Comprehensive unit tests covering all auth guard scenarios - Tests for null user, null token, valid auth states - Tests for all 7 SWR calls (5 in TraderDashboard + 2 in EquityChart) ## Testing - ✅ TypeScript compilation passed - ✅ Vite build passed (2.81s) - ✅ All modifications are additive (no logic changes) - ✅ SWR auto-revalidation ensures data loads after auth completes ## Benefits 1. **No more 401 errors on refresh**: Auth guards prevent premature requests 2. **Cleaner logs**: Backend no longer receives invalid Bearer null requests 3. **Better UX**: No error flashes in console on page load 4. **Consistent pattern**: All authenticated endpoints use same guard logic ## Context This PR supersedes closed PR NoFxAiOS#881, which had conflicts due to PR NoFxAiOS#872 (frontend refactor with React Router). This implementation is based on the latest upstream/dev with the new architecture. Related: PR NoFxAiOS#881 (closed), PR NoFxAiOS#872 (Frontend Refactor) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: the-dev-z <the-dev-z@users.noreply.github.com> Co-authored-by: Claude <noreply@anthropic.com>
1 parent 1334d30 commit 2390d7a

File tree

3 files changed

+379
-7
lines changed

3 files changed

+379
-7
lines changed

web/src/components/EquityChart.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
import useSWR from 'swr'
1313
import { api } from '../lib/api'
1414
import { useLanguage } from '../contexts/LanguageContext'
15+
import { useAuth } from '../contexts/AuthContext'
1516
import { t } from '../i18n/translations'
1617
import {
1718
AlertTriangle,
@@ -36,10 +37,11 @@ interface EquityChartProps {
3637

3738
export function EquityChart({ traderId }: EquityChartProps) {
3839
const { language } = useLanguage()
40+
const { user, token } = useAuth()
3941
const [displayMode, setDisplayMode] = useState<'dollar' | 'percent'>('dollar')
4042

4143
const { data: history, error } = useSWR<EquityPoint[]>(
42-
traderId ? `equity-history-${traderId}` : 'equity-history',
44+
user && token && traderId ? `equity-history-${traderId}` : null,
4345
() => api.getEquityHistory(traderId),
4446
{
4547
refreshInterval: 30000, // 30秒刷新(历史数据更新频率较低)
@@ -49,7 +51,7 @@ export function EquityChart({ traderId }: EquityChartProps) {
4951
)
5052

5153
const { data: account } = useSWR(
52-
traderId ? `account-${traderId}` : 'account',
54+
user && token && traderId ? `account-${traderId}` : null,
5355
() => api.getAccount(traderId),
5456
{
5557
refreshInterval: 15000, // 15秒刷新(配合后端缓存)

0 commit comments

Comments
 (0)