feat: 认证相关

This commit is contained in:
2025-09-06 19:56:13 +08:00
parent 5a25f350c7
commit cd99485c9a
13 changed files with 148 additions and 45 deletions

View File

@@ -63,6 +63,11 @@ export class AuthController {
}
return ctx.session.user;
}
@Get('info')
async info(ctx: Context) {
return ctx.session?.user;
}
}
interface LoginRequestBody {

View File

@@ -1,7 +1,7 @@
import type Koa from 'koa';
import KoaRouter from '@koa/router';
import { getRouteMetadata, getControllerPrefix, type RouteMetadata } from '../decorators/route.ts';
import { createAutoSuccessResponse } from '../middlewares/exception.ts';
import { createSuccessResponse } from '../middlewares/exception.ts';
/**
* 控制器类型
@@ -102,22 +102,16 @@ export class RouteScanner {
*/
private wrapControllerMethod(instance: any, methodName: string) {
return async (ctx: Koa.Context, next: Koa.Next) => {
try {
// 调用控制器方法
const method = instance[methodName];
if (typeof method !== 'function') {
throw new Error(`控制器方法 ${methodName} 不存在或不是函数`);
}
// 绑定this并调用方法
const result = await method.call(instance, ctx, next);
// 如果控制器返回了数据,则包装成统一响应格式
ctx.body = createAutoSuccessResponse(result);
} catch (error) {
// 错误由全局异常处理中间件处理
throw error;
// 调用控制器方法
const method = instance[methodName];
if (typeof method !== 'function') {
ctx.throw(401, 'Not Found')
}
// 绑定this并调用方法
const result = await method.call(instance, ctx, next) ?? null;
ctx.body = createSuccessResponse(result);
};
}

View File

@@ -0,0 +1,23 @@
import type Koa from 'koa';
import type { Middleware } from './types.ts';
export class Authorization implements Middleware {
private readonly ignoreAuth = [
'/api/auth/login',
'/api/auth/info',
'/api/auth/url',
];
apply(app: Koa) {
app.use(async (ctx: Koa.Context, next: Koa.Next) => {
console.log('ctx.path', ctx.path)
if (this.ignoreAuth.includes(ctx.path)) {
return next();
}
if (ctx.session.isNew) {
ctx.throw(401, 'Unauthorized');
}
await next();
});
}
}

View File

@@ -122,7 +122,7 @@ export class Exception implements Middleware {
*/
export function createSuccessResponse<T>(
data: T,
message = '操作成功',
message = 'success',
): ApiResponse<T> {
return {
code: 0,
@@ -132,24 +132,6 @@ export function createSuccessResponse<T>(
};
}
/**
* 创建成功响应的辅助函数(自动设置消息)
*/
export function createAutoSuccessResponse<T>(data: T): ApiResponse<T> {
let message = '操作成功';
// 根据数据类型自动生成消息
if (Array.isArray(data)) {
message = `获取列表成功,共${data.length}条记录`;
} else if (data && typeof data === 'object') {
message = '获取数据成功';
} else if (data === null || data === undefined) {
message = '操作完成';
}
return createSuccessResponse(data, message);
}
/**
* 创建失败响应的辅助函数
*/

View File

@@ -5,6 +5,7 @@ import { Session } from './session.ts';
import { CORS } from './cors.ts';
import { HttpLogger } from './logger.ts';
import type Koa from 'koa';
import { Authorization } from './Authorization.ts';
/**
* 初始化中间件
@@ -20,10 +21,12 @@ export function initMiddlewares(app: Koa) {
// Session 中间件需要在请求体解析之前注册
new Session().apply(app);
new CORS().apply(app);
new Authorization().apply(app);
// 请求体解析中间件
new BodyParser().apply(app);
new CORS().apply(app);
new Router().apply(app);
}

Binary file not shown.