106 lines
2.7 KiB
TypeScript
106 lines
2.7 KiB
TypeScript
import NextAuth, { AuthOptions } from "next-auth"
|
||
import CredentialsProvider from "next-auth/providers/credentials"
|
||
import type { User } from "next-auth"
|
||
import bcrypt from 'bcryptjs'
|
||
import { db } from '@/lib/db'
|
||
|
||
// 认证配置
|
||
const authOptions: AuthOptions = {
|
||
providers: [
|
||
// 邮箱密码登录
|
||
CredentialsProvider({
|
||
name: 'credentials',
|
||
credentials: {
|
||
email: { label: "邮箱", type: "email", placeholder: "user@example.com" },
|
||
password: { label: "密码", type: "password" }
|
||
},
|
||
async authorize(credentials): Promise<User | null> {
|
||
try {
|
||
if (!credentials?.email || !credentials?.password) {
|
||
console.log('❌ 登录失败: 缺少邮箱或密码')
|
||
return null
|
||
}
|
||
|
||
// 从数据库查询用户
|
||
const user = await db.findUserByEmail(credentials.email)
|
||
|
||
if (!user) {
|
||
console.log('❌ 登录失败: 用户不存在 -', credentials.email)
|
||
return null
|
||
}
|
||
|
||
// 使用 bcrypt 验证密码
|
||
const isValidPassword = await bcrypt.compare(
|
||
credentials.password,
|
||
user.password
|
||
)
|
||
|
||
if (!isValidPassword) {
|
||
console.log('❌ 登录失败: 密码错误 -', credentials.email)
|
||
return null
|
||
}
|
||
|
||
console.log('✅ 登录成功:', {
|
||
id: user.id,
|
||
name: user.name,
|
||
email: user.email,
|
||
})
|
||
|
||
// 返回用户信息(不包含密码)
|
||
return {
|
||
id: user.id.toString(),
|
||
name: user.name,
|
||
email: user.email,
|
||
}
|
||
} catch (error) {
|
||
console.error('登录错误:', error)
|
||
return null
|
||
}
|
||
}
|
||
}),
|
||
],
|
||
|
||
// 自定义页面
|
||
pages: {
|
||
signIn: '/auth/signin',
|
||
// error: '/auth/error',
|
||
// signOut: '/auth/signout',
|
||
},
|
||
|
||
// 回调函数
|
||
callbacks: {
|
||
async jwt({ token, user }) {
|
||
if (user) {
|
||
token.id = user.id
|
||
token.email = user.email
|
||
token.name = user.name
|
||
}
|
||
return token
|
||
},
|
||
async session({ session, token }) {
|
||
if (session.user) {
|
||
session.user.id = token.id as string
|
||
session.user.email = token.email as string
|
||
session.user.name = token.name as string
|
||
}
|
||
return session
|
||
},
|
||
},
|
||
|
||
// 会话策略
|
||
session: {
|
||
strategy: "jwt",
|
||
maxAge: 30 * 24 * 60 * 60, // 30 天
|
||
},
|
||
|
||
// 密钥
|
||
secret: process.env.NEXTAUTH_SECRET,
|
||
|
||
// 调试模式(生产环境设为false)
|
||
debug: process.env.NODE_ENV === 'development',
|
||
}
|
||
|
||
const handler = NextAuth(authOptions)
|
||
|
||
export { handler as GET, handler as POST }
|