Skip to content

12.7 · Authentication & Registration

บทนี้เจาะลึก business logic ของการล็อกอิน การสมัครสมาชิก การลืมรหัสผ่าน และการจัดการ session — flow ที่เชื่อม vtrc-api ↔ cu-central-api ↔ LDAP/AD


ภาพรวม

ด้านค่า
ไฟล์ controllerlib/controllers/auth/auth.js (~340 บรรทัด)
Verificationlib/controllers/verification/verification.js
User mgmtlib/controllers/user/user.js
Repositorylib/repositories/{auth,session,verification}/*.js
Forward controllercentralize/controllers/{auth,verification}.js
Captcha expire5 นาที
JWT expire (vtrc-api)15 นาที
JWT expire (cu-central-api)20 นาที
Public device token expire30 วัน

1. Login flow — login

ที่อยู่: controllers/auth/auth.js:43

1. Client ส่ง:
   - sessionId (lsid), password, clientInfo, apiKey, organization

2. vtrc-api ตรวจ apiKey → map เป็น APP_TYPE (WEB, WEB_ADMIN, MOBILE, ...)

3. checkLoginSession(sessionId) — session ต้อง active (stat=1)

4. signInCD(sessionLogin, password, org) → ส่งต่อไป cu-central-api:
   POST /auth/signin { username, password, org, apiKey }

5. cu-central-api ทำ:
   a. checkApiKey
   b. getEmployeeByEmpCode (MSSQL)
   c. bindAdWithUserAndPassword (LDAP)
   d. generateSignInToken (JWT cu-central-api)
   e. เก็บ session ใน Redis
   f. ส่งกลับ { accessToken, refreshToken, userData: { uid, profileKey, sourceDb } }

6. vtrc-api:
   a. create() — สร้าง User row ใน MariaDB (ถ้ายังไม่มี)
   b. generateToken(userId, accessRole, appType, ...) → JWT vtrc-api
   c. setUserDivision — ผูก division
   d. เก็บ session ใน MariaDB (Session table)

7. ส่งกลับ client: { accessToken, refreshToken }
113:122:vtrc-api/api/src/lib/controllers/auth/auth.js
  const newToken = await generateToken(
    user.userId,
    accessRole,
    appType,
    null,
    result.userData.profileKey,
    result.accessToken,           // JWT cu-central-api
    result.refreshToken,          // refreshToken cu-central-api
    sessionLogin.loginSession.empCode
  );

JWT 2 ตัว

เมื่อ login สำเร็จ — vtrc-api เก็บ JWT ของ cu-central-api ไว้ใน Session table เพื่อใช้ตอน forward ภายหลัง


2. Login bypass — mobile PIN

ที่อยู่: auth.js:51signInAppBypass (auth.js:136)

สำหรับ mobile app ที่ใช้ PIN แทน password:

1. Client ส่ง:
   - authSessionId (UUID)
   - signature (RSA-SHA256)

2. ดึง public key จาก AuthSessionMoblie table

3. verify signature

4. ถ้าผ่าน → signInAppBypass → cu-central-api /auth/signinbypass

5. cu-central-api login ไม่ต้องใช้ password
159:168:vtrc-api/api/src/lib/controllers/auth/auth.js
// concept — RSA verify
const verify = crypto.verify('sha256', data, publicKey, signature)
if (!verify) throw responError('SIGNATURE_INVALID')

3. Registration flow — สมัครสมาชิก

ที่อยู่: controllers/verification/verification.js:10-39

[เริ่มต้น]


1. requestVerify(citizenId, birthDate, org, empCode)
    │   → ส่งต่อ cu-central-api เพื่อตรวจข้อมูลพนักงาน
    │   → ถ้าข้อมูลถูกต้อง → ส่ง verificationCode ไป email/SMS

2. sendVerifyCode (CD)
    │   → verificationCode เก็บใน CD Redis

3. requestSendingOTP(phoneNumber)
    │   → ส่ง OTP ไปเบอร์มือถือ
    │   → OTP เก็บใน CD Redis

4. requestVerifyOTPandSetupPassword(args)
    │   → ตรวจ verificationCode + OTP
    │   → ถ้าผ่าน:
    │     a. create User row ใน vtrc MariaDB
    │     b. create Consent row (policy accept)
    │     c. setupPasswordUserCD — ส่ง password ไปตั้งใน AD/LDAP

[สมัครเสร็จ — พร้อม login]

ที่มา: verification.js:82


4. Forget password flow

ที่อยู่: controllers/user/user.js:126

1. forgetPassword(args)
    │   → profileVerificationCheckerCD({ requestFor: "FORGET_PASSWORD", ...})
    │   → CD ส่ง verificationCode ไป email/SMS

2. checkSMSforgetPassword(args)
    │   → fetchCDProfileVerification — verify code
    │   → ถ้าผ่าน → return verificationCode สำหรับใช้ตอน reset

3. resetPassword(args)
    │   → changePasswordByVerifyCode (CD)
    │   → destroyLoginSession — logout ทุก session

[เปลี่ยนรหัสผ่านเสร็จ]
173:195:vtrc-api/api/src/lib/controllers/user/user.js
export const resetPassword = async (args, context) => {
    const sessionLogin = await checkLoginSession(args.lsid)
    if (sessionLogin.loginSession.stat !== 1) {
        responError('SESSION_INVALID')
    }
    const currentUserRole = await getCurrentRoleUserByEmpCode(sessionLogin.loginSession.empCode, ACCESS_BACK_OFFICE)
    const setData = {
        verificationCode, citizenId, employeeCode, birthDate, 
        password, confirmPassword, org, remainingCount,
        isBackofficeUser: currentUserRole.length <= 0 ? false : true
    }
    const result = await changePasswordByVerifyCode(setData)
    await destroyLoginSession(sessionLogin.loginSessionId)
    return result
}

5. Session management

signOutSystem

ที่อยู่: auth.js:243

1. signOutCD(accessToken) → cu-central-api /auth/signout

2. destroy vtrc session (MariaDB)

3. destroy user division

4. delete NotificationUserSettings (raw SQL)

Multi-device session

vtrc-api แยก session ตาม device:

Deviceใช้โดย
WEBvtrc-web (พนักงาน)
WEB_ADMINvtrc-rc-backoffice (HR)
MOBILEmobile app

user สามารถ login พร้อมกันหลาย device — แต่ละ device มี session แยกกัน

Force logout

ไม่พบ explicit API สำหรับ force logout — มีเพียง forceLoging ซึ่งเป็น logger helper ไม่ใช่ logout


6. Captcha

ที่อยู่: auth.js:304

js
// auth.js:304-310 (concept)
export const captcha = async (context) => {
  const captcha = svgCaptcha.create({ size: 6, noise: 3 })
  await captchaSession.create({
    captchaSessionId: uuid,
    text: captcha.text,
    expireDate: moment().add(5, 'minutes').toDate()  // expire 5 นาที
  })
  return captcha.data  // SVG
}
  • Library: svg-captcha
  • Expire: 5 นาที
  • ใช้ก่อน login (verify ใน checkLoginSession)

7. Domain lists — รายชื่อหน่วยงาน

324:vtrc-api/api/src/lib/controllers/auth/auth.js
// concept
export const domainLists = async (context) => {
  return await signInDomains()  // cu-central-api query
}

cu-central-api ส่งรายการ org ที่ login ได้ — เพื่อ frontend แสดงเป็น dropdown ในหน้า login


8. Login session — loginSession table

ก่อน login จริง — client ต้อง verify ตัวเองผ่าน verifyEmpCodeLogin ก่อน เพื่อสร้าง loginSession:

1. verifyEmpCodeLogin(empCode) → สร้าง loginSession (stat=1)

2. login(sessionId, password, ...)

3. ใช้ loginSession.empCode ในการยืนยัน

9. JWT generation

ที่อยู่: lib/repositories/auth/auth.js:96

96:102:vtrc-api/api/src/lib/repositories/auth/auth.js
jwt.sign(
  { id: sessionId, uid: userId },
  JWT_SECRET,
  { expiresIn: JWT_EXP, issuer: JWT_ISSUER, jwtid }
)
// default: JWT_EXP='15m', JWT_ISSUER='redcross.or.th:vtrc'

10. Magic numbers / hardcoded values

Valueความหมายที่มา
5 นาทีcaptcha expireauth.js:307
15 นาทีJWT vtrc-api expireenv JWT_EXP
20 นาทีJWT cu-central-api expireenv CD
30 วันpublic device token expirenotification.js:113
'WEB', 'WEB_ADMIN', 'MOBILE'APP_TYPEconfig.js

11. Cross-service calls

vtrc-api functioncu-central-api endpointวัตถุประสงค์
signInCDPOST /auth/signinLDAP auth
signInByPassPOST /auth/signinbypassbypass auth (mobile)
refreshTokenPOST /auth/tokenrefresh JWT
signOutCDPOST /auth/signoutrevoke session
profileVerificationCheckerCDGraphQLforget password check
setupPasswordUserCDGraphQLตั้ง password ใน AD
requestOtpCDGraphQLส่ง OTP
sendVerifyCodeByCDGraphQLส่ง verificationCode
fetchCDProfileVerificationGraphQLverify code
changePasswordByVerifyCodeGraphQLเปลี่ยน password

12. ข้อระวังทั้งหมด

1. signInbypass endpoint ใน CD

เปิดอยู่ใน cu-central-api — ถ้าแก้โค้ดผิด อาจเป็น backdoor

2. Multi-device login

ไม่จำกัดจำนวน device — user สามารถ login พร้อมกันหลายเครื่อง

3. ไม่มี rate limit

ไม่จำกัดครั้งที่ login ผิด — ควรมี (cu-central-api อาจจำกัด แต่ vtrc-api ไม่ได้ทำเอง)

4. LoginSession stat=1 hard-coded

stat=1 หมายถึง active — ถ้าเปลี่ยน enum ต้องแก้ทุกที่

ไม่ได้ track version — ถ้า policy เปลี่ยน user เก่าไม่ต้องยินยอมใหม่


13. Summary — auth domain

ด้านทำใน vtrc-apiส่งต่อ cu-central-api
Login orchestrationใช่
LDAP authใช่
JWT issue (vtrc-api)ใช่
JWT issue (cu-central-api)ใช่
Session storeใช่ (MariaDB)ใช่ (Redis)
Captchaใช่
Registrationใช่ (orchestration)ใช่ (verify, setup password)
Forget/reset passwordใช่ (orchestration)ใช่ (verify, change)
Multi-device sessionใช่

ขั้นตอนถัดไป

ไป บท 11.8 Delegate & Role