ขั้นตอน login / เลือกบริษัท / refresh / logout
ผู้ใช้พิสูจน์ตัวตนกับ Main Database ของ Tenant ตัวเอง (โมเดลผู้เช่าหลายราย: Tenant, Provider, Main DB, Company (Multi-tenant model)). ถ้าเข้าได้บริษัทเดียว ระบบออก session ทันที; ถ้าเข้าได้หลายบริษัท ระบบออก pre-auth token ให้ไปเรียก /auth/select-company อีกครั้ง. รายละเอียดชนิดโทเค็นอยู่ที่ JWT session token และการเพิกถอน (JWT + revocation store).
ทำงานอย่างไร
1) POST /auth/login (identity/handler.go:76)
- body:
{"provider","dataGroup","username","password"}(handler.go:32-37) — ถ้า JSON พัง → 400. Service.Login(service.go:51):ResolveConnection(provider)ไม่พบ → 401 ข้อความกลางinvalid provider, data group, username or password(ไม่บอกว่าผิดตรงไหน,service.go:22-25).- คำนวณ Main DB
smlerpmain<lower(provider)>แล้วFindByCode:SELECT ... FROM sml_user_list WHERE UPPER(user_code) = UPPER($1)(เทียบชื่อผู้ใช้แบบไม่สนตัวพิมพ์เหมือนระบบเดิม,postgres_repository.go:42-66);user_level/active_statusเป็น NULL → ถือเป็น 0 (ไม่ active). user.Authenticate(password)(domain/identity/identity.go:64): ต้องactive_status = 1; ถ้าuser_passwordเป็น bcrypt hash ($2a$/$2b$/$2y$) ใช้bcrypt.CompareHashAndPassword, ไม่ใช่ก็เทียบ plaintext แบบ constant-time (รองรับข้อมูลเก่า) (:62-71).AccessibleCompanies(provider main DB, dataGroup, user.Code)(SQL อยู่postgres_repository.go:132-175): JOINsml_database_list_user_and_groupกับsml_database_listโดยuser_or_group_status = 0(COALESCE NULL → 1 = ไม่อนุญาต) และเรียงตามroworder.- ผลตามจำนวนบริษัท: 0 → 403
no accessible company for this data group; 1 →IssueSessionได้accessToken+refreshTokenทันที; มากกว่า 1 →IssuePreAuthTokenพร้อมรายการcompanies(code,name) (service.go:68-105).
- รูปผลลัพธ์:
{"session":{"accessToken","refreshToken"}}หรือ{"preAuthToken","companies":[...]}(handler.go:39-60).
2) POST /auth/select-company (service.go:113)
body preAuthToken + companyCode. ตรวจ pre-auth token → คิวรีรายการบริษัทใหม่ ไม่เชื่อรายการที่ client เคยได้ → ถ้า companyCode ไม่อยู่ในรายการ (เทียบไม่สนตัวพิมพ์) → 401 → อ่าน level ล่าสุดของผู้ใช้ (:141-146) → IssueSession.
3) GET /auth/me (ต้อง Auth)
GetProfile คิวรีผู้ใช้/บริษัทสดจาก Main DB ทุกครั้ง (service.go:231) จึงจับกรณีผู้ใช้ถูกปิด/ถอนสิทธิ์ระหว่าง session ได้ แม้ token ยังใช้ได้.
4) POST /auth/refresh (service.go:254)
ตรวจ refresh token (รวมเช็กว่าถูกเพิกถอนหรือยัง) → verifySession ตรวจซ้ำว่าผู้ใช้ยัง active และยังเข้าบริษัทนั้นได้ (:194-228) → เพิกถอน session เก่า → ออกคู่ token ใหม่ด้วย level ล่าสุด (rotation).
5) POST /auth/logout (service.go:287)
ตรวจ refresh token แล้วเพิกถอน jti ของ session — ทำให้ access token ที่ออกมาคู่กันใช้ไม่ได้ทันทีด้วย (ใช้ jti เดียวกัน) (ADR-0004 การเพิกถอน session ตอน logout (RevocationStore)).
กติกา/ข้อควรระวัง
- สิทธิ์เข้าบริษัทคิดจากแถวที่
user_or_group_code= ผู้ใช้โดยตรงเท่านั้น (ไม่รวมกลุ่ม) ขณะที่สิทธิ์เมนูรวมแถวกลุ่ม (สิทธิ์เมนูและ middleware RequireRight (Menu rights / permission)). levelใน access token อัปเดตเฉพาะตอนselect-companyและrefresh— ถ้าเปลี่ยนระดับผู้ใช้กลางอายุ access token (15 นาที) จะยังเป็นค่าเก่า.- ข้อความ error ของ login เหมือนกันทุกสาเหตุ แต่เวลาตอบอาจต่างกัน (bcrypt เฉพาะ user ที่พบ) (อนุมาน ยังไม่ได้วัด).
CONTEXT.mdอธิบายรหัสผ่านเป็น plaintext แต่โค้ดรองรับ bcrypt ด้วย (HashPasswordในidentity.go:50) — เอกสารล้าสมัยบางส่วน ให้ยึดโค้ด.- ไม่มีการจำกัดอัตราการลอง login ในชั้นนี้ (ไม่พบ rate limiter ใน
router.go/identity) (ยังไม่ยืนยันว่ามีที่ proxy). - ADR: ADR-0003 ข้อมูลผู้ใช้และสิทธิ์อยู่ใน DB ของแต่ละผู้เช่า ไม่ใช่ control-plane.
ที่มาในโค้ด
backend/internal/application/identity/service.go:22-25,51-111—Login.backend/internal/application/identity/service.go:113-160—SelectCompany.backend/internal/application/identity/service.go:194-228,254-300—verifySession,Refresh,Logout.backend/internal/domain/identity/identity.go:43-72— bcrypt/plaintext และAuthenticate.backend/internal/adapter/outbound/identity/postgres_repository.go:42,132— SQL ผู้ใช้/บริษัท.backend/internal/adapter/inbound/http/identity/handler.go:32-60,76,123,164,206,239— DTO และ handler.
ดูเพิ่ม
ภาพรวม Backend Go ของ SML Ai Account (Backend overview) · JWT session token และการเพิกถอน (JWT + revocation store) · โมเดลผู้เช่าหลายราย: Tenant, Provider, Main DB, Company (Multi-tenant model) · สิทธิ์เมนูและ middleware RequireRight (Menu rights / permission) · ADR-0003 ข้อมูลผู้ใช้และสิทธิ์อยู่ใน DB ของแต่ละผู้เช่า ไม่ใช่ control-plane · สารบัญ ADR ของ backend (Architecture Decision Records)