สมอง SML

คลังความรู้ / หลังบ้าน Go

#backend#security#permission#identity#middleware

สิทธิ์เมนูและ middleware RequireRight

หลัง Auth ยืนยันตัวตนแล้ว บาง route ต้องมีสิทธิ์เมนูด้วย: /process/*, /query/exec, /query/execBatch, /blob/insert (Router, middleware และแผนผัง route ทั้งหมดของ backend (chi router)). สิทธิ์โหลดสดจาก Main Database ทุกคำขอ (ไม่ฝังใน JWT) แล้วเทียบกับ "สิทธิ์ที่ route ต้องการ".

ทำงานอย่างไร

  1. 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)).
  2. ชนิด Right (permission.go:15-22): Read, Write (= Add หรือ Edit), Delete, Admin, Add, Edit. Allows คืน true ทันทีถ้า rights.Admin (:41-58); RightAdmin ที่ผู้ใช้ไม่ใช่ Admin = ไม่ผ่านเสมอ.
  3. Service.MenuRights (application/identity/service.go:174):
    • username superadmin (ไม่สนตัวพิมพ์) หรือ level >= 9 (webAdminLevel, :164) → ได้ทุกสิทธิ์ + Admin.
    • นอกนั้นโหลดจาก DB (ข้อ 4) ตาม claims.DatabaseName — ผู้ใช้ไม่มีแถวสิทธิ์เลย = ไม่ได้อะไร.
  4. 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).
  5. แต่ละแถวมี 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); อ่านไม่ได้ = ไม่ให้สิทธิ์.
  6. ผลรวม = OR ข้ามทุกเมนูและทุกแถว (orRights, postgres_repository.go:111) — ไม่ได้เช็กตามรหัสเมนูรายหน้าจอ เพราะ /process ไม่รู้ว่าเมนูไหนเรียก (คอมเมนต์ service.go:168-173).

/process — แมปสิทธิ์ต่อ route

  • process/permission.go:23 routeRights: คีย์ "<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)).

ข้อควรระวัง

ที่มาในโค้ด

  • 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)