@Route("api/v1/org/dotnet") ปรับใช้ API Key

This commit is contained in:
harid 2026-05-25 17:34:24 +07:00
parent 32282b016b
commit eede5f51c4
4 changed files with 106 additions and 3 deletions

View file

@ -40,7 +40,7 @@ import { calculateRetireLaw } from "../interfaces/utils";
import { RequestWithUser } from "../middlewares/user";
@Route("api/v1/org/dotnet")
@Tags("Dotnet")
@Security("bearerAuth")
// @Security("bearerAuth")
@Response(
HttpStatus.INTERNAL_SERVER_ERROR,
"เกิดข้อผิดพลาด ไม่สามารถแสดงรายการได้ กรุณาลองใหม่ในภายหลัง",
@ -73,6 +73,7 @@ export class OrganizationDotnetController extends Controller {
*
*/
@Post("check-citizen")
@Security("internalAuth")
public async CheckCitizen(
@Body()
body: {
@ -90,6 +91,7 @@ export class OrganizationDotnetController extends Controller {
*
*/
@Post("search")
@Security("internalAuth")
public async SearchProfile(
@Body()
body: {
@ -304,6 +306,7 @@ export class OrganizationDotnetController extends Controller {
*
*/
@Post("search-employee")
@Security("internalAuth")
public async SearchProfileEmployee(
@Body()
body: {
@ -488,6 +491,7 @@ export class OrganizationDotnetController extends Controller {
* @param {string} id Id
*/
@Get("org/{id}")
@Security("internalAuth")
async GetOrganizationById(@Path() id: string) {
const orgRoot = await this.orgRootRepo.findOne({
where: { id: id },
@ -497,6 +501,7 @@ export class OrganizationDotnetController extends Controller {
}
@Get("agency/{id}")
@Security("internalAuth")
async GetOrgAgencyById(@Path() id: string) {
const orgRoot = await this.orgRootRepo.findOne({
where: { id: id },
@ -506,6 +511,7 @@ export class OrganizationDotnetController extends Controller {
}
@Get("go-agency/{id}")
@Security("internalAuth")
async GetOrgGoAgencyById(@Path() id: string) {
const orgRoot = await this.orgRootRepo.findOne({
where: { id: id },
@ -521,6 +527,7 @@ export class OrganizationDotnetController extends Controller {
*
*/
@Get("get-profileId")
@Security("bearerAuth")
async getProfileInbox(@Request() request: { user: Record<string, any> }) {
let profile: any;
//OFF
@ -556,6 +563,7 @@ export class OrganizationDotnetController extends Controller {
* @param {string} keycloakId Id keycloak
*/
@Get("keycloak-old/{keycloakId}")
@Security("internalAuth")
async GetProfileByKeycloakIdAsyncOld(@Path() keycloakId: string) {
const profile = await this.profileRepo.findOne({
relations: [
@ -1355,6 +1363,7 @@ export class OrganizationDotnetController extends Controller {
}
@Get("keycloak/{keycloakId}")
@Security("internalAuth")
async GetProfileByKeycloakIdAsync(@Path() keycloakId: string) {
/* =========================
* 1. Load profile
@ -1783,6 +1792,7 @@ export class OrganizationDotnetController extends Controller {
}
@Get("by-keycloak/{keycloakId}")
@Security("internalAuth")
async NewGetProfileByKeycloakIdAsync(@Path() keycloakId: string) {
/* =========================
* 1. Load profile
@ -2017,6 +2027,7 @@ export class OrganizationDotnetController extends Controller {
// เพิ่มที่อยู่ปัจจุบัน + ตำแหน่งหัวหน้า
@Get("by-keycloak2/{keycloakId}")
@Security("internalAuth")
async NewGetProfileByKeycloak2IdAsync(@Path() keycloakId: string) {
/* =========================
* 1. Load profile
@ -2358,8 +2369,11 @@ export class OrganizationDotnetController extends Controller {
* @param {string} keycloakId keycloakId profile
*/
@Get("check-keycloak/{keycloakId}")
@Security("internalAuth")
async GetProfileForProcessCheckInAsync(@Path() keycloakId: string) {
try {
console.log(`[check-keycloak] START - keycloakId=${keycloakId}`);
/* =========================
* 1. Load profile (Officer)
* ========================= */
@ -2379,6 +2393,8 @@ export class OrganizationDotnetController extends Controller {
// Employee
if (!profile) {
console.log(`[check-keycloak] OFFICER_NOT_FOUND - keycloakId=${keycloakId}, checking EMPLOYEE`);
const empProfile = await this.profileEmpRepo.findOne({
where: { keycloak: keycloakId },
relations: {
@ -2392,7 +2408,12 @@ export class OrganizationDotnetController extends Controller {
},
},
});
if (!empProfile) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูล");
if (!empProfile) {
console.log(`[check-keycloak] EMPLOYEE_NOT_FOUND - keycloakId=${keycloakId}`);
throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูล");
}
const currentHolder = empProfile.current_holders?.find(
(x) =>
x.orgRevision?.orgRevisionIsDraft === false &&
@ -2426,9 +2447,15 @@ export class OrganizationDotnetController extends Controller {
child4DnaId: currentHolder?.orgChild4?.ancestorDNA ?? null,
};
console.log(
`[check-keycloak] SUCCESS_EMPLOYEE - keycloakId=${keycloakId}, profileType=EMPLOYEE`,
);
return new HttpSuccess(mapProfile);
}
console.log(`[check-keycloak] OFFICER_FOUND - keycloakId=${keycloakId}`);
/* =========================================
* 2. current holder (Officer)
* ========================================= */
@ -2467,6 +2494,10 @@ export class OrganizationDotnetController extends Controller {
child4DnaId: currentHolder?.orgChild4?.ancestorDNA ?? null,
};
console.log(
`[check-keycloak] SUCCESS_OFFICER - keycloakId=${keycloakId}, profileType=OFFICER`,
);
return new HttpSuccess(mapProfile);
} catch (error: any) {
// Log เฉพาะ unexpected errors (ไม่ใช่ HttpError)
@ -2485,6 +2516,7 @@ export class OrganizationDotnetController extends Controller {
* @param {string} keycloakId keycloakId profile
*/
@Get("user-logs/{keycloakId}")
@Security("internalAuth")
async UserLogs(@Path() keycloakId: string) {
/* =========================
* 1. Load profile
@ -2564,6 +2596,7 @@ export class OrganizationDotnetController extends Controller {
* @param {string} profileId Id profile
*/
@Get("profile/{profileId}")
@Security("internalAuth")
async GetProfileByProfileIdAsync(@Path() profileId: string) {
const profile = await this.profileRepo.findOne({
relations: [
@ -3233,6 +3266,7 @@ export class OrganizationDotnetController extends Controller {
* @param {string} citizenId citizen Id
*/
@Get("citizenId/{citizenId}")
@Security("internalAuth")
async GetProfileByCitizenIdAsync(@Path() citizenId: string) {
const profile = await this.profileRepo.findOne({
relations: [
@ -3887,6 +3921,7 @@ export class OrganizationDotnetController extends Controller {
* @param {string} keycloakId Id keycloak
*/
@Get("root/officer/{rootId}")
@Security("internalAuth")
async GetProfileByRootIdAsync(@Path() rootId: string) {
const profiles = await this.profileRepo.find({
relations: [
@ -4199,6 +4234,7 @@ export class OrganizationDotnetController extends Controller {
* @param {string} keycloakId Id keycloak
*/
@Get("root/employee/{rootId}")
@Security("internalAuth")
async GetProfileByRootIdEmpAsync(@Path() rootId: string) {
const profiles = await this.profileEmpRepo.find({
relations: [
@ -4403,6 +4439,7 @@ export class OrganizationDotnetController extends Controller {
* @param {string} keycloakId Id keycloak
*/
@Post("find/employee/position")
@Security("internalAuth")
async GetProfileByPositionEmpAsync(
@Body()
body: {
@ -4732,6 +4769,7 @@ export class OrganizationDotnetController extends Controller {
* @param {string} keycloakId Id keycloak
*/
@Get("user-fullname/{keycloakId}")
@Security("internalAuth")
async GetUserFullName(@Path() keycloakId: string) {
const profile = await this.profileRepo.findOne({
where: { keycloak: keycloakId },
@ -4750,6 +4788,7 @@ export class OrganizationDotnetController extends Controller {
* @param {string} keycloakId Id keycloak
*/
@Get("user-oc/{keycloakId}")
@Security("internalAuth")
async getProfileByKeycloak(@Path() keycloakId: string) {
const profile = await this.profileRepo.findOne({
where: { keycloak: keycloakId },
@ -4801,6 +4840,7 @@ export class OrganizationDotnetController extends Controller {
* @param {string} keycloakId Id keycloak
*/
@Get("user-oc-all/{keycloakId}")
@Security("internalAuth")
async getAllProfileByKeycloak(@Path() keycloakId: string) {
const profile = await this.profileRepo.findOne({
where: { keycloak: keycloakId },
@ -4968,6 +5008,7 @@ export class OrganizationDotnetController extends Controller {
* @param {string} ocId Id
*/
@Get("root-oc/{ocId}")
@Security("internalAuth")
async GetRootOcId(@Path() ocId: string) {
const orgRoot = await this.orgRootRepo.findOne({
where: { id: ocId },
@ -4984,6 +5025,7 @@ export class OrganizationDotnetController extends Controller {
*
*/
@Get("keycloak")
@Security("internalAuth")
async GetProfileWithKeycloak() {
const profile = await this.profileRepo.find({
where: { keycloak: Not(IsNull()) },
@ -5193,6 +5235,7 @@ export class OrganizationDotnetController extends Controller {
*
*/
@Get("keycloak-employee")
@Security("internalAuth")
async GetProfileWithKeycloakEmployee() {
const profile = await this.profileEmpRepo.find({
where: { keycloak: Not(IsNull()) || Not("") },
@ -5321,6 +5364,7 @@ export class OrganizationDotnetController extends Controller {
*
*/
@Post("keycloak-all-officer")
@Security("internalAuth")
async PostProfileWithKeycloakAllOfficer(
@Body()
body: {
@ -5491,6 +5535,7 @@ export class OrganizationDotnetController extends Controller {
*
*/
@Post("keycloak-all-officer/date")
@Security("internalAuth")
async PostProfileWithKeycloakAllOfficerDate(
@Body()
body: {
@ -5669,6 +5714,7 @@ export class OrganizationDotnetController extends Controller {
*
*/
@Post("none-validate-keycloak-all-officer")
@Security("internalAuth")
async PostProfileWithNoneValidateKeycloakAllOfficer(
@Body()
body: {
@ -5838,6 +5884,7 @@ export class OrganizationDotnetController extends Controller {
*
*/
@Post("find-node-name")
@Security("internalAuth")
async findNodeName(
@Body()
body: {
@ -5946,6 +5993,7 @@ export class OrganizationDotnetController extends Controller {
*
*/
@Post("officer-by-admin-role")
@Security("internalAuth")
async GetOfficersByAdminRole(
@Body()
body: {
@ -6283,6 +6331,7 @@ export class OrganizationDotnetController extends Controller {
*
*/
@Post("keycloak-all-employee")
@Security("internalAuth")
async PostProfileWithKeycloakAllEmployee(
@Body()
body: {
@ -6436,6 +6485,7 @@ export class OrganizationDotnetController extends Controller {
*
*/
@Post("none-validate-keycloak-all-employee")
@Security("internalAuth")
async PostProfileWithNoneValidateKeycloakAllEmployee(
@Body()
body: {
@ -6589,6 +6639,7 @@ export class OrganizationDotnetController extends Controller {
*
*/
@Post("employee-by-admin-role")
@Security("internalAuth")
async GetEmployeesByAdminRole(
@Body()
body: {
@ -6929,8 +6980,9 @@ export class OrganizationDotnetController extends Controller {
* @summary admin
*/
@Post("employee-by-admin-rolev2")
@Security("internalAuth")
async GetEmployeesByAdminRoleV2(
@Request() req: RequestWithUser,
// @Request() req: RequestWithUser, // ไม่ได้ใช้
@Body()
body: {
node: number;
@ -7199,6 +7251,7 @@ export class OrganizationDotnetController extends Controller {
*
*/
@Put("update-dutytime")
@Security("bearerAuth")
async UpdateDutyTimeAsync(
@Request() req: RequestWithUser,
@Body()
@ -7241,6 +7294,7 @@ export class OrganizationDotnetController extends Controller {
*
*/
@Post("insignia/Dumb")
@Security("bearerAuth")
public async newInsignia(@Request() req: RequestWithUser, @Body() body: CreateProfileInsignia) {
if (!body.profileId) {
throw new HttpError(HttpStatus.BAD_REQUEST, "กรุณากรอก profileId");
@ -7317,6 +7371,7 @@ export class OrganizationDotnetController extends Controller {
* @param {string} keycloakId Id keycloak
*/
@Get("profile-leave/keycloak/{keycloakId}")
@Security("internalAuth")
async GetProfileLeaveByKeycloakIdAsync(@Path() keycloakId: string) {
const CURRENT_DATE = await AppDataSource.query("SELECT CURRENT_DATE() as today");
let _currentDate = CURRENT_DATE[0].today;
@ -7604,6 +7659,7 @@ export class OrganizationDotnetController extends Controller {
}
@Post("profile-leave/keycloak")
@Security("internalAuth")
async GetProfileLeaveReportByKeycloakIdAsync(
@Body() body: { keycloakId: string; report?: string },
) {
@ -7908,6 +7964,7 @@ export class OrganizationDotnetController extends Controller {
* @param {string} type ( )
*/
@Post("find/insignia-requests-profile/{type}")
@Security("internalAuth")
async GetInsigniaRequestsProfileAsync(
@Path() type: string,
@Body()
@ -8037,6 +8094,7 @@ export class OrganizationDotnetController extends Controller {
*
*/
@Post("officer-by-admin-rolev2")
@Security("internalAuth")
async GetOfficersByAdminRoleV2(
@Body()
body: {
@ -8260,6 +8318,7 @@ export class OrganizationDotnetController extends Controller {
*
*/
@Post("officer-by-admin-rolev3")
@Security("internalAuth")
async GetOfficersByAdminRoleV3(
@Body()
body: {
@ -8606,6 +8665,7 @@ export class OrganizationDotnetController extends Controller {
*
*/
@Post("officer-by-admin-rolev4")
@Security("internalAuth")
async GetOfficersByAdminRoleV4(
@Body()
body: {
@ -8882,6 +8942,7 @@ export class OrganizationDotnetController extends Controller {
*
*/
@Post("find-staff")
@Security("internalAuth")
async findHigher(
@Body()
requestBody: {

View file

@ -4,6 +4,7 @@ import { createDecoder, createVerifier } from "fast-jwt";
import HttpError from "../interfaces/http-error";
import HttpStatus from "../interfaces/http-status";
import { handleWebServiceAuth } from "./authWebService";
import { handleInternalAuth } from "./authInternal";
if (!process.env.AUTH_PUBLIC_KEY && !process.env.AUTH_REALM_URL) {
throw new Error("Require keycloak AUTH_PUBLIC_KEY or AUTH_REALM_URL.");
@ -39,6 +40,11 @@ export async function expressAuthentication(
return { preferred_username: "bypassed" };
}
// เพิ่มการจัดการสำหรับ Internal Authentication (.NET service)
if (securityName === "internalAuth") {
return await handleInternalAuth(request);
}
// เพิ่มการจัดการสำหรับ Web Service Authentication
if (securityName === "webServiceAuth") {
return await handleWebServiceAuth(request);

View file

@ -0,0 +1,30 @@
import * as express from "express";
import HttpError from "../interfaces/http-error";
import HttpStatus from "../interfaces/http-status";
// Internal Authentication (สำหรับ Internal Service เช่น .NET)
// ตรวจสอบ API Key จาก Environment Variable (API_KEY)
export async function handleInternalAuth(request: express.Request) {
// รองรับ header หลายรูปแบบ
const apiKey =
request.headers["api-key"] || request.headers["apikey"];
if (!apiKey || typeof apiKey !== "string") {
throw new HttpError(HttpStatus.UNAUTHORIZED, "API Key is required");
}
// ตรวจสอบ API Key จาก Environment Variable (API_KEY)
if (apiKey !== process.env.API_KEY) {
console.log(`[InternalAuth] Invalid API key attempt: ${apiKey.substring(0, 5)}...`);
throw new HttpError(HttpStatus.UNAUTHORIZED, "Invalid API Key");
}
console.log(`[InternalAuth] Authentication successful`);
return {
sub: "internal_service",
preferred_username: "internal_service",
name: "Internal Service",
internalKey: true,
};
}

View file

@ -29,6 +29,12 @@
"name": "X-API-Key",
"description": "API KEY สำหรับ Web Service",
"in": "header"
},
"internalAuth": {
"type": "apiKey",
"name": "api-key",
"description": "API KEY สำหรับ Internal Service (.NET, HRMS)",
"in": "header"
}
},
"tags": [