156 lines
5.3 KiB
TypeScript
156 lines
5.3 KiB
TypeScript
import db from '@/lib/db/client';
|
|
import { hashPassword } from '@/lib/password';
|
|
import { generateAccessToken } from '@/lib/token';
|
|
import { createRoute, z } from '@hono/zod-openapi';
|
|
import { isNil } from 'lodash';
|
|
|
|
import type { AuthItem } from './type';
|
|
|
|
import {
|
|
createBodyRequest,
|
|
createErrorResult,
|
|
createHonoApp,
|
|
createServerErrorResponse,
|
|
createSuccessResponse,
|
|
createUnauthorizedErrorResponse,
|
|
createValidatorErrorResponse,
|
|
} from '../common/utils';
|
|
import {
|
|
authItemSchema,
|
|
authLoginRequestSchema,
|
|
authLoginResponseSchema,
|
|
createUserSchema,
|
|
} from './schema';
|
|
import { passport, verifyJWT } from './utils';
|
|
|
|
const tags = ['auth'];
|
|
const app = createHonoApp();
|
|
export const authApi = app
|
|
.openapi(
|
|
createRoute({
|
|
tags,
|
|
method: 'get',
|
|
summary: '获取用户信息',
|
|
path: '/profile',
|
|
responses: {
|
|
...createSuccessResponse(
|
|
'获取成功',
|
|
z
|
|
.object({
|
|
result: z.boolean(),
|
|
data: authItemSchema.or(z.null()),
|
|
})
|
|
.openapi('获取用户信息响应数据'),
|
|
),
|
|
...createServerErrorResponse(),
|
|
},
|
|
}),
|
|
async (c) => {
|
|
try {
|
|
const isAuthenticated = await verifyJWT(c);
|
|
|
|
if (!isAuthenticated) return c.json({ result: false, data: null }, 200);
|
|
const { id } = c.var.user;
|
|
const user = await db.user.findUnique({
|
|
where: { id },
|
|
select: {
|
|
id: true,
|
|
username: true,
|
|
email: true,
|
|
createdAt: true,
|
|
updatedAt: true,
|
|
},
|
|
});
|
|
if (isNil(user)) return c.json({ result: false, data: null }, 200);
|
|
return c.json({ result: true, data: user }, 200);
|
|
} catch (error) {
|
|
return c.json(createErrorResult('获取用户失败', error), 500);
|
|
}
|
|
},
|
|
)
|
|
.openapi(
|
|
createRoute({
|
|
tags,
|
|
summary: '用戶註冊',
|
|
method: 'post',
|
|
path: '/signup',
|
|
request: createBodyRequest(createUserSchema),
|
|
responses: {
|
|
...createSuccessResponse('Login success', authLoginResponseSchema),
|
|
...createValidatorErrorResponse(),
|
|
...createServerErrorResponse(),
|
|
},
|
|
}),
|
|
async (c) => {
|
|
const data = await c.req.json();
|
|
const validatedData = await createUserSchema.safeParseAsync(data);
|
|
try {
|
|
if (validatedData.success) {
|
|
const user = await db.user.create({
|
|
data: {
|
|
...validatedData.data,
|
|
password: hashPassword(validatedData.data.password),
|
|
},
|
|
});
|
|
const token = generateAccessToken(user);
|
|
return c.json({ token }, 200);
|
|
}
|
|
return c.json(createErrorResult('参数验证失败', validatedData.error), 400);
|
|
} catch (error) {
|
|
return c.json(createErrorResult('服务器错误', error), 500);
|
|
}
|
|
},
|
|
)
|
|
.openapi(
|
|
createRoute({
|
|
tags,
|
|
summary: '用戶登入',
|
|
method: 'post',
|
|
path: '/login',
|
|
request: createBodyRequest(authLoginRequestSchema),
|
|
responses: {
|
|
...createSuccessResponse('登录成功', authLoginResponseSchema),
|
|
...createValidatorErrorResponse(),
|
|
...createUnauthorizedErrorResponse('认证失败'),
|
|
...createServerErrorResponse(),
|
|
},
|
|
}),
|
|
async (c) => {
|
|
const body = await c.req.json();
|
|
const validatedData = authLoginRequestSchema.safeParse(body);
|
|
if (!validatedData.success) {
|
|
return c.json(createErrorResult('参数验证失败', validatedData.error), 400);
|
|
}
|
|
const authReq = {
|
|
...c.req.raw,
|
|
body: validatedData.data,
|
|
};
|
|
return new Promise((resolve) => {
|
|
passport.authenticate('local', (err: any, user: AuthItem, info: any) => {
|
|
if (err)
|
|
return err.code === 401
|
|
? resolve(c.json(createErrorResult('认证失败', err), 401))
|
|
: resolve(c.json(createErrorResult('服务器错误', err), 500));
|
|
const token = generateAccessToken(user);
|
|
|
|
return resolve(c.json({ token }, 200));
|
|
})(authReq, (c.res as any).raw);
|
|
});
|
|
},
|
|
)
|
|
.openapi(
|
|
createRoute({
|
|
tags,
|
|
summary: '用戶列表',
|
|
method: 'get',
|
|
path: '/',
|
|
responses: {
|
|
...createSuccessResponse('用户列表', z.array(createUserSchema)),
|
|
},
|
|
}),
|
|
async (c) => {
|
|
const users = await db.user.findMany();
|
|
return c.json(users, 200);
|
|
},
|
|
);
|