feat: 认证相关
This commit is contained in:
@@ -63,6 +63,11 @@ export class AuthController {
|
||||
}
|
||||
return ctx.session.user;
|
||||
}
|
||||
|
||||
@Get('info')
|
||||
async info(ctx: Context) {
|
||||
return ctx.session?.user;
|
||||
}
|
||||
}
|
||||
|
||||
interface LoginRequestBody {
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
23
apps/server/middlewares/authorization.ts
Normal file
23
apps/server/middlewares/authorization.ts
Normal 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();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建失败响应的辅助函数
|
||||
*/
|
||||
|
||||
@@ -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.
Reference in New Issue
Block a user