Hair Keeper v1.0.0:一个高度集成、深度定制、约定优于配置的全栈Web应用模板,旨在保持灵活性的同时提供一套基于成熟架构的开发底座,自带身份认证、权限控制、丰富前端组件、文件上传、后台任务、智能体开发等丰富功能,提供AI开发辅助,免于纠结功能如何实现,可快速上手专注于业务逻辑
This commit is contained in:
123
src/server/auth.ts
Normal file
123
src/server/auth.ts
Normal file
@@ -0,0 +1,123 @@
|
||||
import 'server-only'
|
||||
import { NextAuthOptions } from "next-auth"
|
||||
import type { User as NextAuthUser } from "next-auth"
|
||||
import CredentialsProvider from "next-auth/providers/credentials"
|
||||
import bcrypt from "bcryptjs"
|
||||
import { db } from "./db"
|
||||
|
||||
export const authOptions: NextAuthOptions = {
|
||||
providers: [
|
||||
CredentialsProvider({
|
||||
name: "credentials",
|
||||
credentials: {
|
||||
id: { label: "用户ID", type: "text" },
|
||||
password: { label: "密码", type: "password" }
|
||||
},
|
||||
async authorize(credentials, req): Promise<NextAuthUser | null> {
|
||||
if (!credentials?.id || !credentials?.password) {
|
||||
return null
|
||||
}
|
||||
|
||||
try {
|
||||
// 查找用户
|
||||
const user = await db.user.findUnique({
|
||||
where: {
|
||||
id: credentials.id
|
||||
},
|
||||
include: {
|
||||
roles: {
|
||||
include: { permissions: true }
|
||||
},
|
||||
dept: true
|
||||
}
|
||||
})
|
||||
|
||||
if (!user) {
|
||||
return null
|
||||
}
|
||||
|
||||
// 验证密码
|
||||
const isPasswordValid = await bcrypt.compare(credentials.password, user.password)
|
||||
|
||||
|
||||
if (!isPasswordValid) {
|
||||
return null
|
||||
}
|
||||
|
||||
// 更新最近登录时间
|
||||
await db.user.update({
|
||||
where: { id: user.id },
|
||||
data: { lastLoginAt: new Date() }
|
||||
})
|
||||
|
||||
// 返回用户信息、角色和权限
|
||||
const roles = user.roles.map((r) => r.name)
|
||||
const permissions = Array.from(
|
||||
new Set(user.roles.flatMap((r) =>
|
||||
r.permissions.map((p) => p.name)
|
||||
))
|
||||
)
|
||||
return {
|
||||
id: user.id,
|
||||
name: user.name,
|
||||
status: user.status,
|
||||
deptCode: user.deptCode,
|
||||
roles,
|
||||
permissions,
|
||||
isSuperAdmin: user.isSuperAdmin
|
||||
} as any
|
||||
} catch (error) {
|
||||
console.error("Auth error:", error)
|
||||
return null
|
||||
}
|
||||
}
|
||||
})
|
||||
],
|
||||
session: {
|
||||
strategy: "jwt",
|
||||
maxAge: 30 * 24 * 60 * 60, // 30 days
|
||||
},
|
||||
jwt: {
|
||||
maxAge: 30 * 24 * 60 * 60, // 30 days
|
||||
},
|
||||
pages: {
|
||||
signIn: "/login",
|
||||
},
|
||||
callbacks: {
|
||||
async jwt({ token, user }) {
|
||||
// 初次登录时,将用户信息保存到JWT token中
|
||||
if (user) {
|
||||
const u = user as any
|
||||
token = {
|
||||
...token,
|
||||
id: u.id,
|
||||
name: u.name,
|
||||
status: u.status,
|
||||
deptCode: u.deptCode,
|
||||
roles: u.roles,
|
||||
permissions: u.permissions,
|
||||
isSuperAdmin: u.isSuperAdmin,
|
||||
}
|
||||
}
|
||||
return token
|
||||
},
|
||||
async session({ session, token }) {
|
||||
// 将JWT token中的信息传递给session
|
||||
if (session.user) {
|
||||
const t = token as any
|
||||
session.user = {
|
||||
...session.user,
|
||||
id: t.id,
|
||||
name: t.name,
|
||||
status: t.status,
|
||||
deptCode: t.deptCode,
|
||||
roles: t.roles,
|
||||
permissions: t.permissions,
|
||||
isSuperAdmin: t.isSuperAdmin,
|
||||
}
|
||||
}
|
||||
return session
|
||||
}
|
||||
},
|
||||
secret: process.env.NEXTAUTH_SECRET,
|
||||
}
|
||||
Reference in New Issue
Block a user