From e0de2ed25142a179111e8b97ed3492c6aa9c043f Mon Sep 17 00:00:00 2001 From: waruneeauy Date: Thu, 7 Aug 2025 17:14:56 +0700 Subject: [PATCH] updated api web service --- src/controllers/ApiManageController.ts | 11 +++-- src/middlewares/auth.ts | 6 +++ src/middlewares/authWebService.ts | 56 ++++++++++++++++++++++++++ src/middlewares/user.ts | 8 ++++ tsoa.json | 6 +++ 5 files changed, 84 insertions(+), 3 deletions(-) create mode 100644 src/middlewares/authWebService.ts diff --git a/src/controllers/ApiManageController.ts b/src/controllers/ApiManageController.ts index fb0daf46..71bdd01e 100644 --- a/src/controllers/ApiManageController.ts +++ b/src/controllers/ApiManageController.ts @@ -334,7 +334,8 @@ export class ApiManageController extends Controller { @Request() req: RequestWithUser, @Query("page") page: number = 1, @Query("pageSize") pageSize: number = 10, - @Query() searchKeyword: string = "", + @Query() keyword: string = "", + @Query() system: "registry" | "registry_emp" | "registry_temp" | "organization" | "" = "", ): Promise { try { if (!req.user.role.includes("SUPER_ADMIN")) { @@ -356,13 +357,17 @@ export class ApiManageController extends Controller { "apiName.lastUpdatedAt", ]); - if (searchKeyword?.trim()) { + if (keyword?.trim()) { queryBuilder.where( "(apiName.name LIKE :keyword OR apiName.code LIKE :keyword OR apiName.pathApi LIKE :keyword)", - { keyword: `%${searchKeyword.trim()}%` }, + { keyword: `%${keyword.trim()}%` }, ); } + if (system) { + queryBuilder.andWhere("apiName.system = :system", { system }); + } + const [apiNames, total] = await queryBuilder .skip(offset) .take(pageSize) diff --git a/src/middlewares/auth.ts b/src/middlewares/auth.ts index bf62b28a..396ada4d 100644 --- a/src/middlewares/auth.ts +++ b/src/middlewares/auth.ts @@ -3,6 +3,7 @@ import { createDecoder, createVerifier } from "fast-jwt"; import HttpError from "../interfaces/http-error"; import HttpStatus from "../interfaces/http-status"; +import { handleWebServiceAuth } from "./authWebService"; if (!process.env.AUTH_PUBLIC_KEY && !process.env.AUTH_REALM_URL) { throw new Error("Require keycloak AUTH_PUBLIC_KEY or AUTH_REALM_URL."); @@ -30,6 +31,11 @@ export async function expressAuthentication( return { preferred_username: "bypassed" }; } + // เพิ่มการจัดการสำหรับ Web Service Authentication + if (securityName === "webServiceAuth") { + return await handleWebServiceAuth(request); + } + if (securityName !== "bearerAuth") throw new Error("ไม่ทราบวิธีการยืนยันตัวตน"); const token = request.headers["authorization"]?.includes("Bearer ") diff --git a/src/middlewares/authWebService.ts b/src/middlewares/authWebService.ts new file mode 100644 index 00000000..fa50b3fe --- /dev/null +++ b/src/middlewares/authWebService.ts @@ -0,0 +1,56 @@ +import { RequestWithUserWebService } from "./user"; +import { AppDataSource } from "../database/data-source"; +import { ApiKey } from "../entities/ApiKey"; +import * as express from "express"; + +import HttpError from "../interfaces/http-error"; +import HttpStatus from "../interfaces/http-status"; + +// เพิ่มฟังก์ชันสำหรับจัดการ Web Service Authentication +export async function handleWebServiceAuth(request: express.Request) { + // ตัวอย่างการใช้ API Key + const apiKey = request.headers["x-api-key"] as string; + + if (!apiKey) { + throw new HttpError(HttpStatus.UNAUTHORIZED, "ไม่พบข้อมูลสำหรับยืนยันตัวตน"); + } + + // ตรวจสอบ API Key กับฐานข้อมูล + const apiKeyData = await AppDataSource.getRepository(ApiKey).findOne({ + select: { id: true, name: true, keyApi: true }, + where: { keyApi: apiKey }, + relations: ["apiNames"], + }); + if (!apiKeyData) { + throw new HttpError(HttpStatus.UNAUTHORIZED, "ไม่สามารถยืนยันตัวตนได้"); + } + + // บันทึก log data สำหรับ web service + if (!request.app.locals.logData) { + request.app.locals.logData = {}; + } + + request.app.locals.logData.id = apiKeyData.id; + request.app.locals.logData.name = apiKeyData.name; + request.app.locals.logData.accessApi = apiKeyData.apiNames.map((x) => x.id) ?? []; + + // ส่งคืนข้อมูลผู้ใช้ที่ยืนยันตัวตน + return { + id: apiKeyData.id, + name: apiKeyData.name, + type: "web-service", + accessApi: apiKeyData.apiNames.map((x) => x.id) ?? [], + }; +} + +export function isPermissionRequest( + request: RequestWithUserWebService, + apiId: string, +): Promise { + // ฟังก์ชันนี้ใช้เพื่อตรวจสอบสิทธิ์ของผู้ใช้ที่ร้องขอ API โดยตรวจสอบว่า user มีสิทธิ์เข้าถึง API ที่ร้องขอหรือไม่ + const hasPermission = request.user.accessApi.includes(apiId); + if (!hasPermission) { + throw new HttpError(HttpStatus.FORBIDDEN, "คุณไม่มีสิทธิ์เข้าถึง API นี้"); + } + return Promise.resolve(hasPermission); +} diff --git a/src/middlewares/user.ts b/src/middlewares/user.ts index a35cdc4a..e5c48d9a 100644 --- a/src/middlewares/user.ts +++ b/src/middlewares/user.ts @@ -11,3 +11,11 @@ export type RequestWithUser = Request & { role: string[]; }; }; + +export type RequestWithUserWebService = Request & { + user: { + id: string; + name: string; + accessApi: string[]; + }; +}; diff --git a/tsoa.json b/tsoa.json index 6cb0cf0d..492907b8 100644 --- a/tsoa.json +++ b/tsoa.json @@ -23,6 +23,12 @@ "name": "Authorization", "description": "Keycloak Bearer Token", "in": "header" + }, + "webServiceAuth": { + "type": "apiKey", + "name": "X-API-Key", + "description": "API KEY สำหรับ Web Service", + "in": "header" } }, "tags": [