This commit is contained in:
D8D Developer
2025-06-27 03:31:29 +00:00
commit d371fbaefa
68 changed files with 11263 additions and 0 deletions

View File

@@ -0,0 +1,15 @@
import { OpenAPIHono } from '@hono/zod-openapi';
import loginRoute from './login/password';
import logoutRoute from './logout';
import meRoute from './me/get';
import registerRoute from './register/create';
import ssoVerify from './sso-verify';
const app = new OpenAPIHono()
.route('/', loginRoute)
.route('/', logoutRoute)
.route('/', meRoute)
.route('/', registerRoute)
.route('/', ssoVerify);
export default app;

View File

@@ -0,0 +1,71 @@
import { createRoute, OpenAPIHono } from '@hono/zod-openapi'
import { AuthService } from '../../../modules/auth/auth.service'
import { UserService } from '../../../modules/users/user.service'
import { z } from 'zod'
import { ErrorSchema } from '../../../utils/errorHandler'
import { AppDataSource } from '../../../data-source'
import { AuthContext } from '../../../types/context'
import { UserSchema } from '@/server/modules/users/user.entity'
const userService = new UserService(AppDataSource)
const authService = new AuthService(userService)
const LoginSchema = z.object({
username: z.string().min(3).openapi({
example: 'admin',
description: '用户名'
}),
password: z.string().min(6).openapi({
example: 'admin123',
description: '密码'
})
})
const UserResponseSchema = UserSchema
const TokenResponseSchema = z.object({
token: z.string().openapi({
example: 'jwt.token.here',
description: 'JWT Token'
}),
user: UserResponseSchema
})
const loginRoute = createRoute({
method: 'post',
path: '/login',
request: {
body: {
content: {
'application/json': {
schema: LoginSchema
}
}
}
},
responses: {
200: {
description: '登录成功',
content: {
'application/json': {
schema: TokenResponseSchema
}
}
},
401: {
description: '用户名或密码错误',
content: {
'application/json': {
schema: ErrorSchema
}
}
}
}
})
const app = new OpenAPIHono<AuthContext>().openapi(loginRoute, async (c) => {
const { username, password } = c.req.valid('json')
const result = await authService.login(username, password)
return c.json(result, 200)
});
export default app

View File

@@ -0,0 +1,68 @@
import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
import { z } from 'zod'
import { AuthContext } from '@/server/types/context';
import { authMiddleware } from '@/server/middleware/auth.middleware';
import { AppDataSource } from '@/server/data-source';
import { AuthService } from '@/server/modules/auth/auth.service';
import { UserService } from '@/server/modules/users/user.service';
import { ErrorSchema } from '@/server/utils/errorHandler';
// 初始化服务
const userService = new UserService(AppDataSource);
const authService = new AuthService(userService);
const SuccessSchema = z.object({
message: z.string().openapi({ example: '登出成功' })
})
// 定义路由
const routeDef = createRoute({
method: 'post',
path: '/logout',
security: [{ Bearer: [] }],
middleware: [authMiddleware],
responses: {
200: {
description: '登出成功',
content: {
'application/json': {
schema: SuccessSchema
}
}
},
401: {
description: '未授权',
content: {
'application/json': {
schema: ErrorSchema
}
}
},
500: {
description: '服务器错误',
content: {
'application/json': {
schema: ErrorSchema
}
}
}
}
});
const app = new OpenAPIHono<AuthContext>().openapi(routeDef, async (c) => {
try {
const token = c.get('token');
const decoded = authService.verifyToken(token);
if (!decoded) {
return c.json({ code: 401, message: '未授权' }, 401);
}
await authService.logout(token);
return c.json({ message: '登出成功' }, 200);
} catch (error) {
console.error('登出失败:', error);
return c.json({ code: 500, message: '登出失败' }, 500);
}
});
export default app;

View File

@@ -0,0 +1,40 @@
import { createRoute, OpenAPIHono } from '@hono/zod-openapi'
import { ErrorSchema } from '@/server/utils/errorHandler'
import { authMiddleware } from '@/server/middleware/auth.middleware'
import { AuthContext } from '@/server/types/context'
import { UserSchema } from '../../../modules/users/user.entity'
const UserResponseSchema = UserSchema.omit({
password: true
});
const routeDef = createRoute({
method: 'get',
path: '/me',
middleware: authMiddleware,
responses: {
200: {
description: '获取当前用户信息成功',
content: {
'application/json': {
schema: UserResponseSchema
}
}
},
401: {
description: '未授权',
content: {
'application/json': {
schema: ErrorSchema
}
}
}
}
})
const app = new OpenAPIHono<AuthContext>().openapi(routeDef, (c) => {
const user = c.get('user')
return c.json(user, 200)
})
export default app

View File

@@ -0,0 +1,76 @@
import { createRoute, OpenAPIHono } from '@hono/zod-openapi'
import { AuthService } from '../../../modules/auth/auth.service'
import { UserService } from '../../../modules/users/user.service'
import { z } from 'zod'
import { AppDataSource } from '../../../data-source'
import { ErrorSchema } from '../../../utils/errorHandler'
import { AuthContext } from '../../../types/context'
const RegisterSchema = z.object({
username: z.string().min(3).openapi({
example: 'john_doe',
description: '用户名'
}),
password: z.string().min(6).openapi({
example: 'password123',
description: '密码'
}),
email: z.string().email().openapi({
example: 'john@example.com',
description: '邮箱'
})
})
const TokenResponseSchema = z.object({
token: z.string().openapi({
example: 'jwt.token.here',
description: 'JWT Token'
}),
user: z.object({
id: z.number(),
username: z.string()
})
})
const userService = new UserService(AppDataSource)
const authService = new AuthService(userService)
const registerRoute = createRoute({
method: 'post',
path: '/register',
request: {
body: {
content: {
'application/json': {
schema: RegisterSchema
}
}
}
},
responses: {
201: {
description: '注册成功',
content: {
'application/json': {
schema: TokenResponseSchema
}
}
},
400: {
description: '用户名已存在',
content: {
'application/json': {
schema: ErrorSchema
}
}
}
}
})
const app = new OpenAPIHono<AuthContext>().openapi(registerRoute, async (c) => {
const { username, password, email } = c.req.valid('json')
const user = await userService.createUser({ username, password, email })
const token = authService.generateToken(user)
return c.json({ token, user }, 201)
})
export default app

View File

@@ -0,0 +1,66 @@
import { createRoute, OpenAPIHono } from '@hono/zod-openapi'
import { AuthService } from '@/server/modules/auth/auth.service'
import { UserService } from '@/server/modules/users/user.service'
import { ErrorSchema } from '@/server/utils/errorHandler'
import { AppDataSource } from '@/server/data-source'
import { AuthContext } from '@/server/types/context'
const userService = new UserService(AppDataSource)
const authService = new AuthService(userService)
const routeDef = createRoute({
method: 'get',
path: '/sso-verify',
responses: {
200: {
description: 'SSO验证成功',
headers: {
'X-Username': {
schema: { type: 'string' },
description: '格式化后的用户名'
}
}
},
401: {
description: '未授权或令牌无效',
content: {
'application/json': {
schema: ErrorSchema
}
}
},
500: {
description: '服务器错误',
content: {
'application/json': {
schema: ErrorSchema
}
}
}
}
})
const app = new OpenAPIHono().openapi(routeDef, async (c) => {
try {
const token = c.req.header('Authorization')?.replace('Bearer ', '')
if (!token) {
return c.json({ code: 401, message: '未提供授权令牌' }, 401)
}
try {
const userData = await authService.verifyToken(token)
if (!userData) {
return c.json({ code: 401, message: '无效令牌' }, 401)
}
return c.text('OK', 200)
} catch (tokenError) {
return c.json({ code: 401, message: '令牌验证失败' }, 401)
}
} catch (error) {
return c.json({ code: 500, message: 'SSO验证失败' }, 500)
}
})
export default app

View File

@@ -0,0 +1,54 @@
import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
import { UserService } from '@/server/modules/users/user.service';
import { z } from 'zod';
import { authMiddleware } from '@/server/middleware/auth.middleware';
import { ErrorSchema } from '@/server/utils/errorHandler';
import { AppDataSource } from '@/server/data-source';
import { AuthContext } from '@/server/types/context';
const userService = new UserService(AppDataSource);
const DeleteParams = z.object({
id: z.coerce.number().openapi({
param: { name: 'id', in: 'path' },
example: 1,
description: '用户ID'
})
});
const routeDef = createRoute({
method: 'delete',
path: '/{id}',
middleware: [authMiddleware],
request: {
params: DeleteParams
},
responses: {
204: {
description: '用户删除成功'
},
404: {
description: '用户不存在',
content: { 'application/json': { schema: ErrorSchema } }
},
500: {
description: '服务器错误',
content: { 'application/json': { schema: ErrorSchema } }
}
}
});
const app = new OpenAPIHono<AuthContext>().openapi(routeDef, async (c) => {
try {
const { id } = c.req.valid('param');
await userService.deleteUser(id);
return c.body(null, 204);
} catch (error) {
return c.json({
code: 500,
message: error instanceof Error ? error.message : '删除用户失败'
}, 500);
}
});
export default app;

View File

@@ -0,0 +1,59 @@
import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
import { UserService } from '@/server/modules/users/user.service';
import { z } from 'zod';
import { authMiddleware } from '@/server/middleware/auth.middleware';
import { ErrorSchema } from '@/server/utils/errorHandler';
import { AppDataSource } from '@/server/data-source';
import { AuthContext } from '@/server/types/context';
import { UserSchema } from '@/server/modules/users/user.entity';
const userService = new UserService(AppDataSource);
const GetParams = z.object({
id: z.string().openapi({
param: { name: 'id', in: 'path' },
example: '1',
description: '用户ID'
})
});
const routeDef = createRoute({
method: 'get',
path: '/{id}',
middleware: [authMiddleware],
request: {
params: GetParams
},
responses: {
200: {
description: '成功获取用户详情',
content: { 'application/json': { schema: UserSchema } }
},
404: {
description: '用户不存在',
content: { 'application/json': { schema: ErrorSchema } }
},
500: {
description: '服务器错误',
content: { 'application/json': { schema: ErrorSchema } }
}
}
});
const app = new OpenAPIHono<AuthContext>().openapi(routeDef, async (c) => {
try {
const { id } = c.req.valid('param');
const user = await userService.getUserById(parseInt(id));
if (!user) {
return c.json({ code: 404, message: '用户不存在' }, 404);
}
return c.json(user, 200);
} catch (error) {
return c.json({
code: 500,
message: error instanceof Error ? error.message : '获取用户详情失败'
}, 500);
}
});
export default app;

View File

@@ -0,0 +1,77 @@
import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
import { UserService } from '@/server/modules/users/user.service';
import { z } from 'zod';
import { authMiddleware } from '@/server/middleware/auth.middleware';
import { ErrorSchema } from '@/server/utils/errorHandler';
import { AppDataSource } from '@/server/data-source';
import { AuthContext } from '@/server/types/context';
import { UserSchema } from '@/server/modules/users/user.entity';
const userService = new UserService(AppDataSource);
const UpdateParams = z.object({
id: z.coerce.number().openapi({
param: { name: 'id', in: 'path' },
example: 1,
description: '用户ID'
})
});
const UpdateUserSchema = UserSchema.omit({
id: true,
createdAt: true,
updatedAt: true
}).partial();
const routeDef = createRoute({
method: 'put',
path: '/{id}',
middleware: [authMiddleware],
request: {
params: UpdateParams,
body: {
content: {
'application/json': {
schema: UpdateUserSchema
}
}
}
},
responses: {
200: {
description: '用户更新成功',
content: { 'application/json': { schema: UserSchema } }
},
400: {
description: '无效输入',
content: { 'application/json': { schema: ErrorSchema } }
},
404: {
description: '用户不存在',
content: { 'application/json': { schema: ErrorSchema } }
},
500: {
description: '服务器错误',
content: { 'application/json': { schema: ErrorSchema } }
}
}
});
const app = new OpenAPIHono<AuthContext>().openapi(routeDef, async (c) => {
try {
const { id } = c.req.valid('param');
const data = c.req.valid('json');
const user = await userService.updateUser(id, data);
if (!user) {
return c.json({ code: 404, message: '用户不存在' }, 404);
}
return c.json(user, 200);
} catch (error) {
return c.json({
code: 500,
message: error instanceof Error ? error.message : '更新用户失败'
}, 500);
}
});
export default app;

108
src/server/api/users/get.ts Normal file
View File

@@ -0,0 +1,108 @@
import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
import { UserService } from '../../modules/users/user.service';
import { z } from 'zod';
import { authMiddleware } from '../../middleware/auth.middleware';
import { ErrorSchema } from '../../utils/errorHandler';
import { AppDataSource } from '../../data-source';
import { AuthContext } from '../../types/context';
import { UserSchema } from '../../modules/users/user.entity';
const userService = new UserService(AppDataSource);
const PaginationQuery = z.object({
page: z.coerce.number().int().positive().default(1).openapi({
example: 1,
description: '页码从1开始'
}),
pageSize: z.coerce.number().int().positive().default(10).openapi({
example: 10,
description: '每页数量'
}),
keyword: z.string().optional().openapi({
example: 'admin',
description: '搜索关键词(用户名/昵称/手机号)'
})
});
const UserListResponse = z.object({
data: z.array(UserSchema),
pagination: z.object({
total: z.number().openapi({
example: 100,
description: '总记录数'
}),
current: z.number().openapi({
example: 1,
description: '当前页码'
}),
pageSize: z.number().openapi({
example: 10,
description: '每页数量'
})
})
});
const listUsersRoute = createRoute({
method: 'get',
path: '/',
middleware: [authMiddleware],
request: {
query: PaginationQuery
},
responses: {
200: {
description: '成功获取用户列表',
content: {
'application/json': {
schema: UserListResponse
}
}
},
400: {
description: '参数错误',
content: {
'application/json': {
schema: ErrorSchema
}
}
},
500: {
description: '获取用户列表失败',
content: {
'application/json': {
schema: ErrorSchema
}
}
}
}
});
const app = new OpenAPIHono<AuthContext>().openapi(listUsersRoute, async (c) => {
try {
const { page, pageSize, keyword } = c.req.valid('query');
const [users, total] = await userService.getUsersWithPagination({
page,
pageSize,
keyword
});
return c.json({
data: users,
pagination: {
total,
current: page,
pageSize
}
}, 200);
} catch (error) {
if (error instanceof z.ZodError) {
return c.json({ code: 400, message: '参数错误' }, 400);
}
return c.json({
code: 500,
message: error instanceof Error ? error.message : '获取用户列表失败'
}, 500);
}
});
export default app;

View File

@@ -0,0 +1,15 @@
import { OpenAPIHono } from '@hono/zod-openapi';
import listUsersRoute from './get';
import createUserRoute from './post';
import getUserByIdRoute from './[id]/get';
import updateUserRoute from './[id]/put';
import deleteUserRoute from './[id]/delete';
const app = new OpenAPIHono()
.route('/', listUsersRoute)
.route('/', createUserRoute)
.route('/', getUserByIdRoute)
.route('/', updateUserRoute)
.route('/', deleteUserRoute);
export default app;

View File

@@ -0,0 +1,69 @@
import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
import { UserService } from '../../modules/users/user.service';
import { z } from 'zod';
import { authMiddleware } from '../../middleware/auth.middleware';
import { ErrorSchema } from '../../utils/errorHandler';
import { AppDataSource } from '../../data-source';
import { AuthContext } from '../../types/context';
import { UserSchema } from '@/server/modules/users/user.entity';
const userService = new UserService(AppDataSource);
const CreateUserSchema = UserSchema.omit({
id: true,
createdAt: true,
updatedAt: true,
})
const createUserRoute = createRoute({
method: 'post',
path: '/',
middleware: authMiddleware,
request: {
body: {
content: {
'application/json': {
schema: CreateUserSchema
}
}
}
},
responses: {
201: {
description: '创建成功',
content: {
'application/json': {
schema: UserSchema
}
}
},
400: {
description: '输入数据无效',
content: {
'application/json': {
schema: ErrorSchema
}
}
},
500: {
description: '服务器错误',
content: {
'application/json': {
schema: ErrorSchema
}
}
}
}
});
const app = new OpenAPIHono<AuthContext>().openapi(createUserRoute, async (c) => {
try {
const data = c.req.valid('json');
const user = await userService.createUser(data);
return c.json(user, 201);
} catch (error) {
return c.json({ code: 500, message: '服务器错误' }, 500);
}
});
export default app;