new change

This commit is contained in:
chenZB666
2025-10-09 23:42:41 +08:00
parent e1b73b82a2
commit b96533827e
6 changed files with 215 additions and 72 deletions

View File

@@ -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() {
<div className="w-16 h-1 bg-gradient-to-r from-emerald-500 to-teal-500 mx-auto mt-2 rounded-full"></div>
</CardHeader>
<CardContent className="space-y-6 px-6 pb-8">
<form action="/api/auth/signup" method="post">
<input type="hidden" name="callbackUrl" value={callbackUrl} />
<div className="space-y-2">
<Label htmlFor="username" className="text-gray-700 dark:text-gray-300"></Label>
<Input
id="username"
name="username"
type="text"
placeholder="请输入用户名"
required
className="border-emerald-200 dark:border-emerald-900/30 focus:border-emerald-500 dark:focus:border-emerald-400 transition-all rounded-xl"
/>
</div>
<div className="space-y-2">
<Label htmlFor="email" className="text-gray-700 dark:text-gray-300"></Label>
<Input
id="email"
name="email"
type="email"
placeholder="请输入您的邮箱"
required
className="border-emerald-200 dark:border-emerald-900/30 focus:border-emerald-500 dark:focus:border-emerald-400 transition-all rounded-xl"
/>
</div>
<div className="space-y-2">
<Label htmlFor="password" className="text-gray-700 dark:text-gray-300"></Label>
<Input
id="password"
name="password"
type="password"
placeholder="请输入密码"
required
className="border-emerald-200 dark:border-emerald-900/30 focus:border-emerald-500 dark:focus:border-emerald-400 transition-all rounded-xl"
/>
</div>
<Button
type="submit"
className="w-full mt-6 bg-emerald-600 hover:bg-emerald-700 text-white transition-all duration-300 transform hover:-translate-y-1 shadow-md hover:shadow-lg rounded-xl py-6"
>
</Button>
</form>
{/* 使用统一的认证表单组件 */}
<AuthForm type="register" />
{/* 分割线 */}
<div className="relative my-6">

View File

@@ -325,7 +325,7 @@ MOCK-RSA-KEY-FOR-DEMO-PURPOSES-ONLY
<div className="space-y-3">
<Label htmlFor="character-description" className="text-base font-medium"></Label>
<Input
<textarea
id="character-description"
name="description"
value={characterForm.description}

View File

@@ -7,6 +7,17 @@ import CharacterCenterClient from './CharacterCenterClient';
import { Card, CardContent, CardFooter, CardHeader, CardTitle } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
// 角色类型定义
interface Character {
id: string;
name: string;
skinId: string;
created: string;
level: number;
description?: string;
isActive: boolean;
}
export default async function CharacterCenter() {
// 检查用户登录状态
const session = await getServerSession(authOptions);
@@ -20,7 +31,7 @@ export default async function CharacterCenter() {
const userName = session.user?.name || '玩家';
// 模拟的角色数据
const characters = [];
const characters: Character[] = [];
// 渲染客户端组件
return <CharacterCenterClient userName={userName} characters={characters} />;

View File

@@ -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<Session | null>(null);
const [loading, setLoading] = useState(true);
useEffect(() => {

View File

@@ -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: '注册失败,请稍后再试' };
}
};

View File

@@ -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;
}
}