monorepo/server/auth/api.ts

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);
},
);