## 核心功能 ### 1. 全局认证架构 - 新增 AuthProvider:全局认证上下文,管理登录状态和Modal - 新增 useAuthGuard Hook:提供 requireAuth 认证拦截功能 - 新增 AuthGuard 组件:包装需要认证的组件 - 新增 AuthPrompt 组件:多种样式的登录引导组件 ### 2. 登录体验优化 - LoginModal 已优化为底部抽屉式设计 - 登录成功后自动关闭Modal并恢复用户操作 - 支持队列机制,多个认证检查依次执行 ### 3. 页面架构调整 - 根布局集成 AuthProvider - 移除 Tabs 布局的重定向逻辑 - Explore 页面添加认证保护,显示登录提示 ### 4. API安全增强 - 新增 TokenManager:完整的Token生命周期管理 - 新增 SecureClient:安全API客户端,自动处理认证 - 更新 API 客户端:支持认证头和自动Token刷新 ### 5. 文档完善 - AUTH_SYSTEM.md:完整的认证系统使用指南 - AUTH_UPGRADE_SUMMARY.md:升级总结文档 ## 技术亮点 ✅ TypeScript 完整支持,编译时类型检查 ✅ React 最佳实践,合理使用 Hooks 和 Context ✅ 优雅的错误处理,友好的用户提示 ✅ 流畅的动画效果,原生级用户体验 ## 核心优势 - 流畅:无需页面跳转,Modal即用即走 - 智能:自动检测登录需求,无需手动判断 - 安全:完整Token管理和自动刷新机制 - 灵活:多种认证组件满足不同场景 - 易用:详细文档和示例,快速上手 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
112 lines
2.4 KiB
TypeScript
112 lines
2.4 KiB
TypeScript
import React from 'react';
|
||
import { View, StyleSheet } from 'react-native';
|
||
import { useAuth } from '@/hooks/use-auth';
|
||
import { useAuthGuard } from '@/hooks/use-auth-guard';
|
||
import { ThemedText } from '@/components/themed-text';
|
||
|
||
interface AuthGuardProps {
|
||
children: React.ReactNode;
|
||
fallback?: React.ReactNode;
|
||
showLoginPrompt?: boolean;
|
||
title?: string;
|
||
subtitle?: string;
|
||
}
|
||
|
||
/**
|
||
* 认证守卫组件
|
||
* 用于包装需要登录才能访问的内容
|
||
*
|
||
* @param children - 需要保护的内容
|
||
* @param fallback - 未登录时显示的自定义内容(可选)
|
||
* @param showLoginPrompt - 是否显示默认的登录提示(默认true)
|
||
* @param title - 自定义提示标题
|
||
* @param subtitle - 自定义提示副标题
|
||
*
|
||
* @example
|
||
* ```typescript
|
||
* <AuthGuard>
|
||
* <ProtectedComponent />
|
||
* </AuthGuard>
|
||
*
|
||
* // 自定义提示
|
||
* <AuthGuard
|
||
* title="需要登录"
|
||
* subtitle="登录后即可使用此功能"
|
||
* >
|
||
* <ProtectedComponent />
|
||
* </AuthGuard>
|
||
* ```
|
||
*/
|
||
export function AuthGuard({
|
||
children,
|
||
fallback,
|
||
showLoginPrompt = true,
|
||
title = '需要登录',
|
||
subtitle = '请先登录以继续使用',
|
||
}: AuthGuardProps) {
|
||
const { isAuthenticated, isLoading } = useAuth();
|
||
const { requireAuth } = useAuthGuard();
|
||
|
||
if (isLoading) {
|
||
return <View style={styles.loadingContainer} />;
|
||
}
|
||
|
||
if (!isAuthenticated) {
|
||
if (fallback) {
|
||
return <>{fallback}</>;
|
||
}
|
||
|
||
if (showLoginPrompt) {
|
||
return (
|
||
<View style={styles.promptContainer}>
|
||
<View style={styles.iconContainer}>
|
||
<ThemedText style={styles.lockIcon}>🔒</ThemedText>
|
||
</View>
|
||
<ThemedText style={styles.title}>{title}</ThemedText>
|
||
<ThemedText style={styles.subtitle}>{subtitle}</ThemedText>
|
||
</View>
|
||
);
|
||
}
|
||
|
||
return null;
|
||
}
|
||
|
||
return <>{children}</>;
|
||
}
|
||
|
||
const styles = StyleSheet.create({
|
||
loadingContainer: {
|
||
flex: 1,
|
||
},
|
||
promptContainer: {
|
||
flex: 1,
|
||
alignItems: 'center',
|
||
justifyContent: 'center',
|
||
padding: 32,
|
||
},
|
||
iconContainer: {
|
||
width: 80,
|
||
height: 80,
|
||
borderRadius: 40,
|
||
backgroundColor: 'rgba(0, 122, 255, 0.1)',
|
||
alignItems: 'center',
|
||
justifyContent: 'center',
|
||
marginBottom: 24,
|
||
},
|
||
lockIcon: {
|
||
fontSize: 40,
|
||
},
|
||
title: {
|
||
fontSize: 24,
|
||
fontWeight: '700',
|
||
marginBottom: 12,
|
||
textAlign: 'center',
|
||
},
|
||
subtitle: {
|
||
fontSize: 16,
|
||
opacity: 0.7,
|
||
textAlign: 'center',
|
||
lineHeight: 24,
|
||
},
|
||
});
|