|
|
@@ -0,0 +1,143 @@
|
|
|
+import { createRoute, OpenAPIHono } from '@hono/zod-openapi'
|
|
|
+import { AuthService } from '../modules/auth/auth.service'
|
|
|
+import { UserService } from '../modules/users/user.service'
|
|
|
+import { User } from '../modules/users/user.entity'
|
|
|
+import { z } from 'zod'
|
|
|
+import { HTTPException } from 'hono/http-exception'
|
|
|
+
|
|
|
+// 扩展Context类型
|
|
|
+type AuthContext = {
|
|
|
+ Variables: {
|
|
|
+ user: User
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const app = new OpenAPIHono<AuthContext>()
|
|
|
+const authService = new AuthService()
|
|
|
+const userService = new UserService()
|
|
|
+
|
|
|
+// Schema 定义
|
|
|
+const LoginSchema = z.object({
|
|
|
+ username: z.string().min(3).openapi({
|
|
|
+ example: 'john_doe',
|
|
|
+ description: '用户名'
|
|
|
+ }),
|
|
|
+ password: z.string().min(6).openapi({
|
|
|
+ example: 'password123',
|
|
|
+ description: '密码'
|
|
|
+ })
|
|
|
+})
|
|
|
+
|
|
|
+const RegisterSchema = LoginSchema.extend({
|
|
|
+ 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 loginRoute = createRoute({
|
|
|
+ method: 'post',
|
|
|
+ path: '/auth/login',
|
|
|
+ request: {
|
|
|
+ body: {
|
|
|
+ content: {
|
|
|
+ 'application/json': {
|
|
|
+ schema: LoginSchema
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ responses: {
|
|
|
+ 200: {
|
|
|
+ description: '登录成功',
|
|
|
+ content: {
|
|
|
+ 'application/json': {
|
|
|
+ schema: TokenResponseSchema
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ 401: { description: '用户名或密码错误' }
|
|
|
+ }
|
|
|
+})
|
|
|
+
|
|
|
+app.openapi(loginRoute, async (c) => {
|
|
|
+ const { username, password } = c.req.valid('json')
|
|
|
+ const result = await authService.login(username, password)
|
|
|
+ return c.json(result)
|
|
|
+})
|
|
|
+
|
|
|
+// 注册路由
|
|
|
+const registerRoute = createRoute({
|
|
|
+ method: 'post',
|
|
|
+ path: '/auth/register',
|
|
|
+ request: {
|
|
|
+ body: {
|
|
|
+ content: {
|
|
|
+ 'application/json': {
|
|
|
+ schema: RegisterSchema
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ responses: {
|
|
|
+ 201: {
|
|
|
+ description: '注册成功',
|
|
|
+ content: {
|
|
|
+ 'application/json': {
|
|
|
+ schema: TokenResponseSchema
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ 400: { description: '用户名已存在' }
|
|
|
+ }
|
|
|
+})
|
|
|
+
|
|
|
+app.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)
|
|
|
+})
|
|
|
+
|
|
|
+// 获取当前用户信息路由
|
|
|
+const meRoute = createRoute({
|
|
|
+ method: 'get',
|
|
|
+ path: '/auth/me',
|
|
|
+ security: [{ Bearer: [] }],
|
|
|
+ responses: {
|
|
|
+ 200: {
|
|
|
+ description: '获取成功',
|
|
|
+ content: {
|
|
|
+ 'application/json': {
|
|
|
+ schema: z.object({
|
|
|
+ id: z.number(),
|
|
|
+ username: z.string()
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ 401: { description: '未授权' }
|
|
|
+ }
|
|
|
+})
|
|
|
+
|
|
|
+app.openapi(meRoute, async (c) => {
|
|
|
+ const user = c.get('user')
|
|
|
+ return c.json({
|
|
|
+ id: user.id,
|
|
|
+ username: user.username
|
|
|
+ })
|
|
|
+})
|
|
|
+
|
|
|
+export const authOpenApiApp = app
|