สิทธิ์เมนูและ middleware RequireRight
หลัง Auth ยืนยันตัวตนแล้ว บาง route ต้องมีสิทธิ์เมนูด้วย: /process/*, /query/exec, /query/execBatch, /blob/insert (Router, middleware และแผนผัง route ทั้งหมดของ backend (chi router)). สิทธิ์โหลดสดจาก Main Database ทุกคำขอ (ไม่ฝังใน JWT) แล้วเทียบกับ "สิทธิ์ที่ route ต้องการ".
ทำงานอย่างไร
RequireRight(loader, need)(middleware/permission.go:62): ดึงSessionClaimsจาก context →loader.MenuRights(claims)→need(r)ได้Right→Allows(rights, right); ไม่ผ่าน → 403 พร้อมข้อความไทยของสิทธิ์นั้น (รูปแบบ error และ response ของ API (apperr + response helper)).- ชนิด
Right(permission.go:15-22):Read,Write(= Add หรือ Edit),Delete,Admin,Add,Edit.Allowsคืน true ทันทีถ้าrights.Admin(:41-58);RightAdminที่ผู้ใช้ไม่ใช่ Admin = ไม่ผ่านเสมอ. Service.MenuRights(application/identity/service.go:174):- username
superadmin(ไม่สนตัวพิมพ์) หรือlevel >= 9(webAdminLevel,:164) → ได้ทุกสิทธิ์ +Admin. - นอกนั้นโหลดจาก DB (ข้อ 4) ตาม
claims.DatabaseName— ผู้ใช้ไม่มีแถวสิทธิ์เลย = ไม่ได้อะไร.
- username
UserRepository.MenuRights(outbound/identity/postgres_repository.go:69): ก่อนอ่านจะรันALTER TABLE ... ADD COLUMN IF NOT EXISTS database_nameกับsml_permissions_userและsml_permissions_groupทุกครั้ง (:74-75) แล้วUNION ALL:- แถวของผู้ใช้เอง:
sml_permissions_user(usercode) กรองdatabase_nameตรงกับบริษัทหรือว่าง โดยให้แถวที่ตรงบริษัทมาก่อน แล้วเอาroworderล่าสุด 1 แถว. - แถวของกลุ่มที่ผู้ใช้อยู่:
sml_permissions_groupผ่านsml_user_and_group(group_code/user_code).
- แถวของผู้ใช้เอง:
- แต่ละแถวมี blob
image_file→DecodeMenuRights(menu_rights.go:48): ตัด BOM UTF-8; ถ้าขึ้นต้น{อ่านเป็น JSON{"menus":[{"code","read","add","edit","delete"}]}; ไม่ใช่ก็แปลงจาก XML ของ C# เดิม (_submeid,_isRead,_isAdd,_isEdit,_isDelete); อ่านไม่ได้ = ไม่ให้สิทธิ์. - ผลรวม = OR ข้ามทุกเมนูและทุกแถว (
orRights,postgres_repository.go:111) — ไม่ได้เช็กตามรหัสเมนูรายหน้าจอ เพราะ/processไม่รู้ว่าเมนูไหนเรียก (คอมเมนต์service.go:168-173).
/process — แมปสิทธิ์ต่อ route
process/permission.go:23routeRights: คีย์"<group>/<action>"→ สิทธิ์ (read/write/del/admin). route ที่ไม่อยู่ในแมปต้องเป็น Admin (:20-22,133) เพื่อให้ route ใหม่ล็อกไว้ก่อน.RequiredRight(:57) ปรับตามเนื้อหา body ผ่านpeekJSON(อ่าน body ไม่เกิน 1MB แล้วคืนให้ handler): เช่นreport/runที่มีcustomSql= Admin;stock/rebuildที่ระบุItemCodes= write ไม่ระบุ = Admin;trans/save/doc/saveใช้IsNew→ Add / Edit;master/datalist*ของผู้ใช้อื่น = Admin.
/query/exec, /query/execBatch, /blob/insert
QueryRequiredRight (process/permission.go:138):
| เส้นทาง | สิทธิ์ที่ต้องการ |
|---|---|
/blob/insert |
Write |
/query/exec |
ตามคำนำหน้า SQL: insert→Add, update→Edit, delete→Delete, อื่น ๆ→Write (sqlStatementRight, :171) |
/query/execBatch |
sqlBatchRight (:184): แถว sml_audit_log ดูค่าแรกของ `values (1 |
| body อ่านไม่ออก | Write |
นี่เป็นด่านสิทธิ์เมนู ก่อน นโยบายล็อกเขียนของตาราง (นโยบายล็อกการเขียนผ่าน Query Gateway (Query write policy / lockdown)); ทั้งสองต้องผ่านทั้งคู่.
จัดการสิทธิ์ (admin)
GET/PUT /api/v1/admin/menu-permissions (router.go:234-235, handler ใน admin/menu_permissions.go:46,107) อ่าน/เขียน image_file ของผู้ใช้/กลุ่ม ผ่าน EncodeMenuRights ที่เก็บเฉพาะเมนูที่ให้สิทธิ์อย่างน้อยหนึ่งอย่าง (menu_rights.go:35-43) (Admin API สำหรับจัดการ Provider/ผู้ใช้/ฐานข้อมูล/สิทธิ์เมนู (Admin API)).
ข้อควรระวัง
- เพราะ OR ข้ามเมนู ผู้ใช้ที่มีสิทธิ์ "เพิ่ม" ในเมนูใดเมนูหนึ่งทำ Add ได้ใน route ที่ต้องการ Add ทุกอัน.
ALTER TABLEทุกคำขอเพิ่มภาระ/lock เล็กน้อยบน Main DB และผู้ใช้ DB ต้องมีสิทธิ์ ALTER (ผลถูกทิ้ง_, _ =จึงเงียบเมื่อพลาด).- สิทธิ์เข้าบริษัท (
/auth/login) ใช้แถวผู้ใช้ตรงเท่านั้น แต่สิทธิ์เมนูรวมกลุ่ม (ขั้นตอน login / เลือกบริษัท / refresh / logout (Identity login flow)). - ถ้า
Rightsไม่ถูกส่งเข้า routerqueryWriteGuardจะเป็น nil และ exec/blob ไม่ถูกคุมสิทธิ์เมนู — ในdiส่งเสมอ (สถาปัตยกรรม Hexagonal และ composition root ของ Go backend (Hexagonal Architecture + DI)). - POS routes ไม่ผ่าน
RequireRight(POS Sync API: เครื่อง POS เชื่อมกับ Account (POS device sync)).
ที่มาในโค้ด
backend/internal/adapter/inbound/http/middleware/permission.go:15-86—Right,Allows,RequireRight.backend/internal/application/identity/service.go:162-190—webAdminLevel,MenuRights.backend/internal/adapter/outbound/identity/postgres_repository.go:69-114— SQL สิทธิ์ +orRights.backend/internal/adapter/outbound/identity/menu_rights.go:9-70— โครง JSON/XML และ decode/encode.backend/internal/adapter/inbound/http/process/permission.go:23-136,138-239—routeRights,RequiredRight,QueryRequiredRight,peekJSON.
ดูเพิ่ม
ภาพรวม Backend Go ของ SML Ai Account (Backend overview) · นโยบายล็อกการเขียนผ่าน Query Gateway (Query write policy / lockdown) · JWT session token และการเพิกถอน (JWT + revocation store) · Router, middleware และแผนผัง route ทั้งหมดของ backend (chi router) · ADR-0011 ล็อก SQL เขียนจาก browser: ตารางเงิน/สต๊อก/GL ผ่าน /api/process เท่านั้น · สารบัญ ADR ของ backend (Architecture Decision Records)