new change
This commit is contained in:
@@ -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">
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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} />;
|
||||
|
||||
@@ -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(() => {
|
||||
|
||||
@@ -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: '注册失败,请稍后再试' };
|
||||
}
|
||||
};
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user