68 lines
1.9 KiB
TypeScript
68 lines
1.9 KiB
TypeScript
// server/utils/auth.ts - Better Auth 服务端实例,邮箱密码登录 + 用户 API token
|
||
import { randomBytes } from "node:crypto";
|
||
|
||
import { betterAuth } from "better-auth";
|
||
import { prismaAdapter } from "better-auth/adapters/prisma";
|
||
import type { H3Event } from "h3";
|
||
import { toWebRequest } from "h3";
|
||
|
||
import { prisma } from "~~/server/utils/db";
|
||
|
||
/**
|
||
* Better Auth 全局实例
|
||
*
|
||
* - 使用 Prisma MySQL/MariaDB 适配器
|
||
* - 只启用邮箱/密码登录,无邮箱验证和密码重置(保持最简)
|
||
* - 注册时通过 databaseHook 自动生成 32 位 hex apiToken
|
||
* apiToken 供 OCS 油猴脚本跨域调用 /api/search 时在 body 中携带
|
||
* - apiToken 不允许客户端直接设置(input: false),但随 session 返回给登录用户
|
||
*/
|
||
export const auth = betterAuth({
|
||
database: prismaAdapter(prisma, { provider: "mysql" }),
|
||
|
||
session: {
|
||
expiresIn: 60 * 60 * 24 * 14, // 14 天过期
|
||
updateAge: 60 * 60 * 24 // 每天自动续期
|
||
},
|
||
|
||
emailAndPassword: {
|
||
enabled: true
|
||
},
|
||
|
||
user: {
|
||
additionalFields: {
|
||
apiToken: {
|
||
type: "string",
|
||
required: false,
|
||
// 客户端(signup/updateUser)不能设置此字段,只由 databaseHooks 写入
|
||
input: false
|
||
}
|
||
}
|
||
},
|
||
|
||
databaseHooks: {
|
||
user: {
|
||
create: {
|
||
// 注册时自动生成 apiToken,格式与旧 ACCESS_TOKEN 字段一致(32 位 hex)
|
||
before: async (user) => {
|
||
return {
|
||
data: {
|
||
...user,
|
||
apiToken: randomBytes(16).toString("hex")
|
||
}
|
||
};
|
||
}
|
||
}
|
||
}
|
||
}
|
||
});
|
||
|
||
/**
|
||
* 从 H3 事件中读取 Better Auth session
|
||
*
|
||
* 封装 toWebRequest 转换,避免在每个 handler 中重复导入和调用
|
||
* 未登录或 session 无效时返回 null
|
||
*/
|
||
export const getAuthSession = (event: H3Event) =>
|
||
auth.api.getSession({ headers: toWebRequest(event).headers });
|