AUTHORIZATION MANAGEMENT

Phân quyền rõ ràng, kiểm soát đến từng tài nguyên

Mục lục trang

Vì sao cần phân quyền?

Đảm bảo đúng người, đúng hành động, đúng tài nguyên

Authorization không chỉ kiểm tra user đã đăng nhập. Hệ thống còn phải biết user được làm gì và có được chạm vào tài nguyên cụ thể đó hay không.

Một request đi qua

5 lớp kiểm tra
IdentityPermissionResource
Đúng người
Đúng quyền
Đúng phạm vi

Luồng tổng quát

Từ identity đến quyết định truy cập

5 chặng
  1. 01

    Xác thực identity

    Gateway xác minh JWT bằng JWKS, loại identity header giả và tạo user context đáng tin cậy.

  2. 02

    Kiểm tra permission

    Permissions Guard so grant của user với quyền mà route yêu cầu; thiếu quyền thì dừng tại Gateway.

  3. 03

    Resolve policy hiệu lực

    Auth Service hợp nhất role, assignment, permission và scope đang active thành access profile.

  4. 04

    Kiểm tra resource

    Domain service kiểm tra ownership và scope trên shop, product hoặc resource cụ thể trước mutation.

  5. 05

    Trả trải nghiệm phù hợp

    Request hợp lệ được forward; UI dùng access profile để hiện đúng navigation, còn request sai nhận 401 hoặc 403.

Điểm kiểm soát: frontend chỉ trình bày khả năng; quyết định bảo mật luôn nằm ở Gateway và service sở hữu resource.

Tài liệu chi tiết

Đi từ nơi policy được resolve đến cách quyền được enforce, cache và truy vết.

1Kiến trúc hệ thốngAuth Service sở hữu policy; Gateway truyền context đã xác thực; downstream service kiểm tra ownership trước mutation.
1.1Luồng hoạt động của hệ thốngMột request được phép phải đúng identity, action và scope; một thay đổi policy phải được audit và làm mới access profile.
1.1.1Luồng kiểm tra request · đúng người, đúng quyền, đúng phạm viMột request chỉ chạy business logic sau khi vượt qua identity, permission ở route và ownership/scope trên resource thật.

Request path · sáu chặng

Frontend gửi tín hiệu, backend mới ra quyết định

401 / 403 rõ nghĩa
  1. Bước01

    Client

    Gửi request

    Làm gì?

    Browser gửi Bearer token kèm endpoint, action và dữ liệu cần xử lý. Identity header do client tự gắn chỉ là thông tin tham khảo.

    Tại sao?

    Mọi dữ liệu từ browser đều có thể bị sửa. Nếu tin userId, role hoặc permission do client gửi, người dùng có thể tự nhận danh tính và quyền cao hơn.

    Bước02

    Identity

    Verify JWT

    Làm gì?

    Gateway đọc Bearer token. JWKS (JSON Web Key Set) là endpoint công khai các public key mà hệ thống phát hành token dùng để ký JWT; Gateway lấy đúng key để kiểm tra chữ ký, issuer, audience và thời hạn rồi tạo trusted user context.

    Tại sao?

    JWKS giúp Gateway xác minh token mà không cần biết private key. Khi auth service đổi key, danh sách public key được cập nhật để việc xác minh vẫn an toàn; các service phía sau chỉ nhận danh tính đã kiểm tra.

  2. Bước03

    Route

    Kiểm tra permission

    Xem logic

    Làm gì?

    Permissions Guard đọc permission metadata của route rồi đối chiếu với grant có trong access profile của user. Thiếu grant thì dừng request và trả 403.

    Tại sao?

    JWT chỉ chứng minh user là ai; nó không tự chứng minh user được gọi endpoint nào. Vì vậy đăng nhập thành công vẫn có thể bị chặn ở lớp route.

  3. Bước04

    Proxy

    Forward context

    Làm gì?

    Gateway loại bỏ identity header do browser gửi, sau đó chuyển request cùng trusted user context tới service sở hữu dữ liệu.

    Tại sao?

    Service phía sau chỉ nhận một contract identity thống nhất: user đã xác minh, grant đã kiểm tra và thông tin request cần thiết.

  4. Bước05

    Resource

    Kiểm tra ownership và scope

    Xem logic

    Làm gì?

    Domain service lấy resource thật rồi kiểm tra actor có đúng shop, product hoặc resource hay không; đồng thời xác nhận action nằm trong scope trước khi mutation.

    Tại sao?

    Permission route chỉ cho phép gọi đúng loại endpoint, không cấp quyền lên mọi dữ liệu. User có thể được apply nhưng vẫn không được sửa sản phẩm thuộc shop khác.

  5. Bước06

    Decision

    Cho phép hoặc từ chối

    Làm gì?

    Hệ thống tổng hợp kết quả của identity, route grant và resource scope. Chỉ khi cả ba hợp lệ request mới vào handler nghiệp vụ; nếu không, request kết thúc tại lớp kiểm tra tương ứng.

    Tại sao?

    UI và backend cần phân biệt đúng nguyên nhân: 401 là chưa xác thực được token, còn 403 là đã biết user nhưng user không đủ quyền hoặc không thuộc phạm vi resource.

1.1.2Luồng thay đổi policy · cập nhật xong phải truy vết đượcAdmin thay đổi role-permission; hệ thống ghi audit, tăng version và invalidate access profile cũ.
Bước01

Admin

Xem policy hiện tại

Làm gì?

Admin đọc danh sách role, permission, assignment và scope đang áp dụng cho từng shop hoặc resource.

Tại sao?

Phải biết policy hiện tại trước khi sửa để tránh cấp nhầm quyền, tạo grant trùng hoặc ảnh hưởng ngoài phạm vi quản lý.

Bước02

Command

Gửi yêu cầu đổi policy

Xem logic

Làm gì?

Admin gửi PATCH với grant mới cùng actor context đã xác thực; backend kiểm tra payload và quyền quản trị trước khi ghi.

Tại sao?

Thay đổi policy là một mutation nhạy cảm, nên không thể chỉ dựa vào userId do client gửi hoặc cho mọi user gọi trực tiếp.

Bước03

Trace

Lưu audit và xoá cache cũ

Xem logic

Làm gì?

Sau khi ghi policy, hệ thống lưu actor, before/after change và thời điểm; đồng thời tăng permissionVersion và loại access profile cũ khỏi cache.

Tại sao?

Nếu cache quyền cũ còn tồn tại, request sau đó có thể dùng grant đã bị thu hồi; audit cũng cần đủ dữ liệu để truy lại ai đã đổi gì.

Bước04

Runtime

Tạo lại access profile

Xem logic

Làm gì?

Request tiếp theo resolve lại access profile từ role, assignment, scope và permissionVersion mới; frontend dùng profile đó để cập nhật navigation.

Tại sao?

Quyền vừa đổi chỉ nên xuất hiện sau khi runtime lấy được profile mới, tránh UI hiển thị quyền mà API chưa chấp nhận hoặc ngược lại.

1.2Công nghệ sử dụngCác thành phần phục vụ xác thực, kiểm tra quyền, lưu policy, cache access profile và hiển thị navigation theo quyền hiệu lực.
  • Next.jsAdmin UI
  • NestJSAuth API
  • PostgreSQLPolicy & user data
  • RedisAccess cache
  • KeycloakToken issuer · RS256
  • JWTAccess token · RS256
1.3Các service tham giaAuthorization tách nơi phát hành danh tính, nơi enforce request, nơi quản lý policy và nơi sở hữu resource.
1.3.1Luồng kiểm tra requestRequest đi qua API Gateway, đối chiếu với Keycloak rồi mới được chuyển tới domain service.
  1. 01 · API Gateway

    api-gateway

    JwtAuthGuard xác minh JWT bằng public key từ Keycloak JWKS; PermissionsGuard đọc @RequirePermissions và trả 401/403 trước khi proxy.

  2. 02 · Identity provider

    Keycloak

    Phát hành access token theo realm bin-ecommerce và công bố JWKS endpoint để Gateway kiểm tra chữ ký RS256.

  3. 03 · Domain services

    seller-service / product-service

    Nhận context đã xác thực, rồi tự kiểm tra shop, owner, resource và scope trước khi thực hiện mutation.

1.3.2Quản lý policy và access profileAuth Service đọc policy từ PostgreSQL, dùng Redis để cache profile và trả quyền hiệu lực cho web app.
  1. 01 · Policy API

    auth-service

    Đọc overview, nhận PATCH role-permission, resolve access profile và ghi audit change.

  2. 02 · Source of truth

    PostgreSQL

    Lưu user, role, permission, assignment, scope, navigation và permission audit log.

  3. 03 · Cache

    Redis

    Cache access profile theo userId và permissionVersion; cache chỉ tăng tốc, không thay nguồn policy.

  4. 04 · Client

    web · Next.js

    Gọi profile đã lọc để dựng navigation, default route và màn hình access denied; không tự quyết định quyền.

Ranh giới service: Keycloak phát hành token; API Gateway xác minh và enforce route; Auth Service quản lý policy/profile; domain service enforce resource; web chỉ trình bày kết quả.

2Logic xử lýNăm điểm kiểm soát giải thích cách request được cấp quyền, policy được cập nhật và access profile được làm mới.
2.1Kiểm tra permission trước khi forwardTrước khi request đi vào service, Gateway kiểm tra token đã xác thực có đúng permission mà endpoint yêu cầu hay không.

Nó là gì?

Permission là quyền cho phép một user thực hiện một action cụ thể trên một endpoint, ví dụ xem, tạo, apply hoặc rollback.

Giải quyết bài toán gì?

Đăng nhập chỉ cho biết user là ai, không có nghĩa user được gọi mọi API. Lớp này ngăn request thiếu quyền đi sâu vào service và tránh frontend tự thêm role/permission để nâng quyền.

  1. Bước01

    Route khai báo action cần có

    Decorator @RequirePermissions gắn permission metadata vào endpoint. Ví dụ image optimization tách riêng view, generate, apply và rollback.

  2. Bước02

    PermissionsGuard đối chiếu grant

    Guard đọc trusted context do JwtAuthGuard tạo, lấy access profile của user và tìm grant có code/action khớp route. Permission không lấy từ body hoặc header do browser tự gửi.

  3. Bước03

    Chỉ request hợp lệ mới được forward

    Đủ grant thì Gateway chuyển request cùng context xuống proxy; thiếu grant thì dừng ngay tại Gateway, không để business handler phía sau chạy.

2.2Kiểm tra ownership và scope trên resource thậtCó quyền gọi endpoint chưa đủ; domain service còn phải xác nhận resource thuộc đúng user, shop hoặc phạm vi được phân công.

Nó là gì?

Ownership và scope là giới hạn dữ liệu mà một permission được phép tác động tới: của chính user, của shop, shop được phân công hoặc toàn hệ thống.

Giải quyết bài toán gì?

Một user có thể có permission đúng nhưng vẫn không được sửa resource của shop khác. Domain service cần kiểm tra resource thật để ngăn truy cập chéo dữ liệu.

Permission trả lời “được làm gì?”

Ví dụ SELLER_PRODUCT_UPDATE chỉ nói user được gọi hành động cập nhật product. Nó chưa nói product đó thuộc shop nào.

Scope trả lời “được làm ở đâu?”

Domain service phải lấy resource thật và đối chiếu owner/shop/assignment với actor context trước khi đọc hoặc ghi dữ liệu. Vì vậy UI ẩn nút không thay thế được kiểm tra backend.

Cách đọc: permission xác định action như product.update; scope giới hạn resource mà action đó được phép tác động. Domain service luôn lấy actor từ trusted context và lấy owner/shop từ database, không dùng ownerId hoặc shopId do client tự khai báo.

ScopeÝ nghĩa nghiệp vụDomain lấy và đối chiếuVí dụ trong hệ thốngKết quả khi không đạt
globalAction được phép trên phạm vi toàn hệ thống, không bị giới hạn bởi owner hoặc shop.Gateway/domain vẫn phải thấy đúng permission global; không được suy ra global chỉ vì user có role admin.Tác vụ quản trị policy hoặc dữ liệu dùng chung.403 nếu action không có grant global tương ứng.
ownUser chỉ được thao tác bản ghi mà chính user đó sở hữu.Domain lấy ownerId của resource từ database và so với actorId trong trusted context; ownerId trong body không có giá trị quyết định.Đọc hoặc sửa bản ghi thuộc user hiện tại.Trả 403 trước khi đọc tiếp hoặc thực hiện mutation.
own_shopSeller được thao tác resource thuộc shop mà seller sở hữu/quản lý.Domain lấy shopId của product/resource thật, sau đó đối chiếu với shop membership/ownership đã resolve từ actor.Seller cập nhật product trong shop của mình.Trả 403 và không chạy câu lệnh UPDATE lên resource shop khác.
assigned_shopStaff chỉ được thao tác các shop được phân công trong thời gian còn hiệu lực.Domain kiểm tra assignment đúng actor, đúng shop, chưa revoked/inactive và chưa hết hạn.Staff xử lý dữ liệu của shop được phân công.Trả 403; không tin shopId từ body để chuyển sang shop khác.

Thứ tự bảo vệ: Gateway kiểm tra route permission trước; domain service kiểm tra ownership và scope sau. Chỉ khi cả hai lớp hợp lệ, business logic mới được phép chạy.

2.3Ghi thay đổi role-permission có kiểm soátMọi thay đổi role và permission đều phải xác thực actor, kiểm tra payload và phạm vi trước khi ghi policy.

Nó là gì?

Policy command là request dùng để cấp, gỡ hoặc thay đổi role, permission, assignment và scope trong hệ thống.

Giải quyết bài toán gì?

Đây là thao tác có thể làm thay đổi quyền của nhiều user. Nếu không xác thực actor, payload và phạm vi, admin giả hoặc client có thể tự cấp quyền vượt giới hạn.

Bước 1 · Actor

Xác định ai đang thay đổi

Actor lấy từ JWT context đã verify, không lấy userId do client gửi trong body. Gateway kiểm tra grant quản trị rồi mới chuyển request tới auth-service.

Bước 2 · Payload

Xác định thay đổi

PATCH mô tả role, permission, assignment hoặc scope cần cấp/gỡ. DTO validation loại field sai, thiếu field bắt buộc và dữ liệu ngoài contract.

Bước 3 · Policy check

Kiểm tra phạm vi

Auth Service xác minh admin có được sửa policy của shop/resource đó không, tránh cấp quyền vượt quá phạm vi quản trị.

Bước 4 · Commit

Ghi PostgreSQL

Chỉ khi các kiểm tra đều đạt, auth-service mới commit policy. Lỗi validation, thiếu quyền hoặc sai scope dừng trước mutation.

JWT contextGuard + DTO validationAuth ServicePostgreSQL
2.4Audit thay đổi và vô hiệu access profile cũSau khi policy đổi, hệ thống ghi lại lịch sử và loại access profile cũ để quyền mới có hiệu lực.

Nó là gì?

Audit là nhật ký thay đổi quyền; invalidate là loại access profile cũ khỏi Redis sau khi policy đã thay đổi.

Giải quyết bài toán gì?

Nếu chỉ cập nhật database mà giữ cache cũ, user có thể tiếp tục dùng quyền đã bị thu hồi. Nếu không có audit, hệ thống không trả lời được ai đã cấp/gỡ quyền và thay đổi lúc nào.

  1. Bước 1 · Change

    Commit policy mới

    Role/permission change hợp lệ được ghi vào PostgreSQL, nguồn dữ liệu chuẩn của policy. Bản ghi chỉ được tạo sau khi actor, payload và phạm vi đã qua kiểm tra.

  2. Bước 2 · Audit

    Lưu before/after

    Auth Service ghi actorUserId, nội dung trước/sau, thời điểm và request context để trả lời ai đã đổi gì, đổi lúc nào và đổi trong phạm vi nào.

  3. Bước 3 · Version

    Đánh dấu profile cũ

    permissionVersion tăng sau thay đổi. Profile đang mang version cũ được xem là stale, không còn đại diện cho policy hiện tại.

  4. Bước 4 · Invalidate

    Buộc resolve lại

    Redis bị invalidate; lần /me hoặc /refresh sau phải tạo access profile mới. Quyền vừa bị gỡ không thể tiếp tục sống vô thời hạn trong cache.

Ranh giới dữ liệu: PostgreSQL giữ policy và audit; Redis chỉ giữ bản sao access profile để đọc nhanh. Dù cache có lỗi, JwtAuthGuard, PermissionsGuard và domain ownership check vẫn không bị bỏ qua.

2.5Tạo bảng quyền hiện tại cho userAuth Service hợp nhất danh tính và policy thành bảng quyền hiện tại để web và backend dùng cùng một kết quả.

Nó là gì?

Access profile là “bảng quyền hiện tại” đã được Auth Service tổng hợp cho một user: user là ai, được làm action nào, trên phạm vi nào và thấy khu vực nào trên web.

Giải quyết bài toán gì?

Role, assignment, permission và scope nằm ở nhiều nguồn. Nếu mỗi service tự đọc và tự hiểu khác nhau, UI có thể hiển thị sai quyền hoặc request dùng policy không đồng nhất.

Bước 1 · Identity

Xác định user

Gateway đã xác minh JWT nên Auth Service biết request thuộc user nào. Hệ thống lấy role trong token để tương thích và lấy thêm user-role assignment trong database, nhưng chỉ giữ assignment còn active, chưa revoked và chưa hết hạn.

Bước 2 · Policy

Đọc luật quyền

Auth Service đọc role-permission, grant, scope, area access, navigation và permissionVersion từ PostgreSQL. Đây là policy server-side; user không thể gửi body để tự thêm role hoặc permission.

Bước 3 · Kết quả

Bảng quyền hiện tại của user

Auth Service lọc role không còn hiệu lực rồi merge grant và scope thành access profile. Profile này trả lời được user có action nào, trên phạm vi nào và được hiển thị khu vực nào trong web.

Bổ sung · Cache

Khi nào dùng cache?

Profile được cache theo userId + permissionVersion để không phải join lại role/permission ở mọi lần đọc. Cache chỉ là bản sao tăng tốc; khi version đổi hoặc cache bị invalidate, hệ thống phải đọc policy và tạo profile mới.

Bổ sung · Ví dụ

Khi admin gỡ quyền

Auth Service tăng version và xóa profile cũ; lần /me hoặc /refresh sau không còn grant update, web ẩn nút sửa, nhưng Gateway/domain vẫn kiểm tra quyền độc lập khi seller gọi API.