diff --git a/src/app/(auth)/register/page.tsx b/src/app/(auth)/register/page.tsx index 9d4872e..682990e 100644 --- a/src/app/(auth)/register/page.tsx +++ b/src/app/(auth)/register/page.tsx @@ -1,9 +1,8 @@ 'use client'; -import { Button } from '@/components/ui/button'; -import { Input } from '@/components/ui/input'; -import { Label } from '@/components/ui/label'; +import AuthForm from '@/components/auth/AuthForm'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; +import { Button } from '@/components/ui/button'; import Link from 'next/link'; import Image from 'next/image'; import { useSearchParams } from 'next/navigation'; @@ -65,52 +64,8 @@ export default function RegisterPage() {
-
- - -
- - -
- -
- - -
- -
- - -
- - -
+ {/* 使用统一的认证表单组件 */} + {/* 分割线 */}
diff --git a/src/app/character-center/CharacterCenterClient.tsx b/src/app/character-center/CharacterCenterClient.tsx index 786b795..077b45a 100644 --- a/src/app/character-center/CharacterCenterClient.tsx +++ b/src/app/character-center/CharacterCenterClient.tsx @@ -325,7 +325,7 @@ MOCK-RSA-KEY-FOR-DEMO-PURPOSES-ONLY
- ; diff --git a/src/app/user-home/page.tsx b/src/app/user-home/page.tsx index f4b2ea8..24ca9da 100644 --- a/src/app/user-home/page.tsx +++ b/src/app/user-home/page.tsx @@ -6,9 +6,10 @@ import Link from 'next/link'; import { Button } from '@/components/ui/button'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { getSession } from 'next-auth/react'; +import { Session } from 'next-auth'; export default function UserHome() { - const [session, setSession] = useState(null); + const [session, setSession] = useState(null); const [loading, setLoading] = useState(true); useEffect(() => { diff --git a/src/lib/api/actions.ts b/src/lib/api/actions.ts index 29704e8..cbe8940 100644 --- a/src/lib/api/actions.ts +++ b/src/lib/api/actions.ts @@ -2,7 +2,62 @@ 'use server'; import axios from 'axios'; -const API_URL = process.env.NEXT_PUBLIC_API_URL || '/api'; +// 配置axios实例,统一处理API请求 +const apiClient = axios.create({ + baseURL: process.env.NEXT_PUBLIC_API_URL || '/api', + timeout: 10000, // 设置10秒超时 + headers: { + 'Content-Type': 'application/json', + }, +}); + +// 添加请求拦截器处理认证 +apiClient.interceptors.request.use( + (config) => { + // 可以在这里添加认证token + return config; + }, + (error) => { + return Promise.reject(error); + } +); + +// 添加响应拦截器统一处理错误 +apiClient.interceptors.response.use( + (response) => response, + (error) => { + // 处理常见错误状态码 + if (error.response) { + switch (error.response.status) { + case 401: + // 未授权,可能需要重新登录 + console.error('认证失败,需要重新登录'); + break; + case 403: + // 禁止访问 + console.error('权限不足'); + break; + case 404: + // 资源不存在 + console.error('请求的资源不存在'); + break; + case 500: + // 服务器错误 + console.error('服务器内部错误'); + break; + default: + console.error(`API请求错误: ${error.response.status}`); + } + } else if (error.request) { + // 没有收到响应 + console.error('网络错误,无法连接到服务器'); + } else { + // 请求配置错误 + console.error('请求配置错误:', error.message); + } + return Promise.reject(error); + } +); // 导出退出登录函数 - 供服务器端使用 export const serverSignOut = async () => { @@ -44,11 +99,24 @@ export const login = async (credentials: { }) => { try { // 对于测试环境,可以直接验证测试账号 - const TEST_USERNAME = 'test'; - const TEST_PASSWORD = 'test'; - // 对于测试环境,可以直接验证测试账号 - 支持通过username或email字段登录 + const TEST_USERNAME = process.env.TEST_USERNAME || 'test'; + const TEST_PASSWORD = process.env.TEST_PASSWORD || 'test'; + + // 验证是否为空 + if (!credentials.password) { + return { success: false, error: '请输入密码' }; + } + + // 获取用户名或邮箱字段 const usernameField = credentials.username || credentials.email; - if (usernameField === TEST_USERNAME && credentials.password === TEST_PASSWORD) { + if (!usernameField) { + return { success: false, error: '请输入用户名或邮箱' }; + } + + // 支持通过username或email字段登录测试账号 + if (process.env.NODE_ENV !== 'production' && + usernameField === TEST_USERNAME && + credentials.password === TEST_PASSWORD) { return { success: true, user: { @@ -61,11 +129,20 @@ export const login = async (credentials: { } // 实际环境中调用API - const response = await axios.post(`${API_URL}/auth/login`, credentials); + const response = await apiClient.post('/auth/login', credentials); return { success: true, ...response.data }; } catch (error) { console.error('登录失败:', error); - return { success: false, error: '登录失败,请检查用户名和密码' }; + // 根据错误类型提供更具体的错误信息 + if (error instanceof axios.AxiosError) { + if (error.response?.status === 401) { + return { success: false, error: '用户名或密码错误,请重试' }; + } + if (error.request) { + return { success: false, error: '网络连接失败,请检查您的网络设置' }; + } + } + return { success: false, error: '登录失败,请稍后再试' }; } }; @@ -77,11 +154,56 @@ export const register = async (userData: { minecraftUsername: string; }) => { try { + // 基本验证 + if (!userData.username?.trim()) { + return { success: false, error: '用户名不能为空' }; + } + if (!userData.password?.trim()) { + return { success: false, error: '密码不能为空' }; + } + if (!userData.email?.trim()) { + return { success: false, error: '邮箱不能为空' }; + } + if (!userData.minecraftUsername?.trim()) { + return { success: false, error: 'Minecraft用户名不能为空' }; + } + + // 密码强度检查(简单示例) + if (userData.password.length < 6) { + return { success: false, error: '密码长度至少为6位' }; + } + + // 邮箱格式检查 + const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; + if (!emailRegex.test(userData.email)) { + return { success: false, error: '请输入有效的邮箱地址' }; + } + // 实际环境中调用API - const response = await axios.post(`${API_URL}/auth/register`, userData); + const response = await apiClient.post('/auth/register', userData); return { success: true, ...response.data }; } catch (error) { console.error('注册失败:', error); + // 根据错误类型提供更具体的错误信息 + if (error instanceof axios.AxiosError) { + if (error.response?.status === 400) { + // 从服务器获取具体错误信息 + return { + success: false, + error: error.response.data?.error || '注册信息有误,请检查后重试' + }; + } + if (error.response?.status === 409) { + // 冲突,可能是用户名或邮箱已存在 + return { + success: false, + error: '用户名或邮箱已被注册' + }; + } + if (error.request) { + return { success: false, error: '网络连接失败,请检查您的网络设置' }; + } + } return { success: false, error: '注册失败,请稍后再试' }; } }; \ No newline at end of file diff --git a/src/lib/api/auth.ts b/src/lib/api/auth.ts index f012f4c..18a1a29 100644 --- a/src/lib/api/auth.ts +++ b/src/lib/api/auth.ts @@ -3,7 +3,44 @@ import NextAuth, { AuthOptions } from 'next-auth'; import CredentialsProvider from 'next-auth/providers/credentials'; import axios from 'axios'; -const API_URL = process.env.NEXT_PUBLIC_API_URL || '/api'; +// 配置axios实例,与actions.ts保持一致 +const apiClient = axios.create({ + baseURL: process.env.NEXT_PUBLIC_API_URL || '/api', + timeout: 10000, + headers: { + 'Content-Type': 'application/json', + }, +}); + +// 添加响应拦截器,与actions.ts保持一致 +apiClient.interceptors.response.use( + (response) => response, + (error) => { + if (error.response) { + switch (error.response.status) { + case 401: + console.error('认证失败,需要重新登录'); + break; + case 403: + console.error('权限不足'); + break; + case 404: + console.error('请求的资源不存在'); + break; + case 500: + console.error('服务器内部错误'); + break; + default: + console.error(`API请求错误: ${error.response.status}`); + } + } else if (error.request) { + console.error('网络错误,无法连接到服务器'); + } else { + console.error('请求配置错误:', error.message); + } + return Promise.reject(error); + } +); declare module "next-auth" { interface Session { @@ -26,14 +63,16 @@ export const authOptions: AuthOptions = { password: { label: "密码", type: "password" } }, async authorize(credentials) { - // 默认测试账号 - 用于开发和测试环境 - const TEST_USERNAME = 'test'; - const TEST_PASSWORD = 'test'; + // 测试账号配置 - 从环境变量获取 + const TEST_USERNAME = process.env.TEST_USERNAME || 'test'; + const TEST_PASSWORD = process.env.TEST_PASSWORD || 'test'; try { // 检查是否是测试账号 - 支持通过username或email字段登录 const usernameField = credentials?.username || credentials?.email; - if (usernameField === TEST_USERNAME && credentials?.password === TEST_PASSWORD) { + if (process.env.NODE_ENV !== 'production' && + usernameField === TEST_USERNAME && + credentials?.password === TEST_PASSWORD) { // 返回模拟的测试用户数据 return { id: 'test_user_1', @@ -41,27 +80,42 @@ export const authOptions: AuthOptions = { email: 'test@test.com', minecraftUsername: 'SteveTest' }; - - - } - // 正常的API登录流程 - const response = await axios.post(`${API_URL}/auth/login`, { + // 验证输入 + if (!usernameField || !credentials?.password) { + console.error('用户名/邮箱和密码不能为空'); + return null; + } + + // 正常的API登录流程 - 使用apiClient + const response = await apiClient.post('/auth/login', { username: credentials?.username, + email: credentials?.email, password: credentials?.password }); if (response.data && response.data.user) { return { id: response.data.user.id, - name: response.data.user.username, - email: response.data.user.email + name: response.data.user.name || response.data.user.username, + email: response.data.user.email, + minecraftUsername: response.data.user.minecraftUsername }; } return null; } catch (error) { console.error('认证失败:', error); + // 区分不同类型的错误,提供更好的错误反馈 + if (error instanceof axios.AxiosError) { + if (error.response?.status === 401) { + console.error('用户名或密码错误'); + } else if (error.response?.status === 400) { + console.error('登录信息不完整或格式错误'); + } else if (!error.response) { + console.error('无法连接到认证服务器'); + } + } return null; } }