Quản lý truy cập trong REST server với kbmMW #4

Dựa trên những kiến thức về xây dựng REST server với kbmMW, bây giờ chúng ta cần xem xét cách kiểm soát quyền truy cập của người dùng. Quản lý truy cập về cơ bản là trả lời câu hỏi "ai được phép làm gì".

Trong thế giới dữ liệu, thông tin cần được bảo vệ khỏi những người/tiến trình không được phép đọc, tạo hoặc thay đổi. Ngược lại, chỉ những người/tiến trình đáng tin cậy mới được phép truy cập. Một số dữ liệu có thể được truy cập nhưng không được phép sửa đổi.

kbmMW cung cấp các chức năng tích hợp để giải quyết vấn đề này, với lớp cốt lõi là TkbmMWAuthorizationManager.

Đầu tiên, thêm một TkbmMWAuthorizationManager vào form chính (trong Unit7 của bài viết trước).

Bạn có thể sử dụng trình quản lý ủy quyền độc lập, nhưng thông thường nên kết nối nó với kbmMWServer instance. Thiết lập thuộc tính kbmMWServer1.AuthorizationManager thành kbmMWAuthorizationManager1. Khi đó, mỗi yêu cầu đến server ứng dụng sẽ được kiểm tra quyền truy cập.

Trình quản lý ủy quyền kbmMW hoạt động dựa trên các khái niệm sau:

  • resource (tài nguyên)
  • actor (chủ thể)
  • role (vai trò)
  • authorization (ủy quyền)
  • constraint (ràng buộc)
  • login (đăng nhập)

Resource là bất kỳ đối tượng nào bạn muốn bảo vệ: cơ sở dữ liệu, một đối tượng cụ thể, hoặc chức năng/dịch vụ chỉ được xử lý bởi người được ủy quyền. Resource có thể được nhóm thành cây, cho phép truy cập tự động vào các resource con khi truy cập resource cha.

Actor thường là một người (với thông tin đăng nhập), một tiến trình, hoặc bất kỳ thực thể nào muốn truy cập tài nguyên.

Role là cách phân loại các kiểu truy cập chung. Ví dụ: trong thư viện có role "Người mượn", "Thủ thư", "Quản trị viên". Trong ngân hàng có "Khách hàng", "Giao dịch viên", "Quản lý". Mỗi role có quyền truy cập khác nhau vào các resource. Một actor thường có ít nhất một role, và có thể có nhiều role tùy theo cách đăng nhập hoặc nguồn gốc.

Authorization là "giấy phép" cho phép actor hoặc role truy cập vào một resource cụ thể. Authorization có thể mang giá trị phủ định, ví dụ: từ chối truy cập vào một resource và tất cả resource con của nó.

Constraint là giới hạn áp dụng lên authorization hoặc login. Ví dụ: authorization chỉ có hiệu lực trong một khung giờ nhất định, chỉ cho phép truy cập từ một thiết bị cụ thể, hoặc login chỉ được thực hiện vào ban ngày.

Login là sự khớp giữa actor/password và token đăng nhập. Khi actor đăng nhập, hệ thống kiểm tra tên, mật khẩu, role yêu cầu và các constraint liên quan. Chỉ khi tất cả được xác nhận và cho phép đăng nhập, một token mới được cấp. Mỗi yêu cầu đến server kbmMW đều phải kèm token này.

Hãy định nghĩa hai role cho REST server: "Reader" và "ReadWriter". kbmMW không giới hạn tên role (cũng như resource và actor), miễn là chúng duy nhất trong từng loại.

  • Reader
  • ReadWriter

Dùng code để định nghĩa hai role này (ví dụ trong sự kiện OnCreate của form chính):

kbmMWAuthorizationManager1.AddRole('READER');
kbmMWAuthorizationManager1.AddRole('READWRITER');

Tiếp theo, cần thông báo cho trình quản lý ủy quyền biết các actor tồn tại để kiểm tra khi đăng nhập.

Cách đơn giản là định nghĩa trước actor. Cũng có thể làm trong OnCreate hoặc trước khi server được truy cập lần đầu. Tùy theo nhu cầu, bạn có thể lấy thông tin actor từ database, file cấu hình, LDAP, v.v.

kbmMWAuthorizationManager1.AddActor('HANS','HANSPASSWORD','READER');
kbmMWAuthorizationManager1.AddActor('CHRISTINE','CHRISTINEPASSWORD','READWRITER');

Ở đây, hai actor được định nghĩa với mật khẩu và role mặc định khi đăng nhập (nếu không yêu cầu role khác).

Nếu không muốn định nghĩa trước actor, bạn có thể dùng sự kiện OnLogin của kbmMWAuthorizationManager1 để kiểm tra chúng từ hệ thống khác:

procedure TForm7.kbmMWAuthorizationManager1Login(Sender: TObject;
 const AActorName, ARoleName: string; var APassPhrase: string;
 var AActor: TkbmMWAuthorizationActor; var ARole: TkbmMWAuthorizationRole;
 var AMessage: string);
begin
...
end;

Tham số AActorName là tên actor, ARoleName là role yêu cầu. Nếu actor đã được biết đến, AActor sẽ là instance tương ứng; nếu không, nó là nil và bạn phải tạo mới. Tương tự, ARole có thể nil nếu role không tồn tại; bạn có thể tạo mới TkbmMWAuthorizationRole và trả về. Nhớ thêm actor/role mới vào danh sách Actors/Roles của manager. Nếu trả về nil cho AActor hoặc ARole, đăng nhập thất bại; tham số AMessage có thể chứa thông báo lỗi.

Sau khi định nghĩa actor và role, trình quản lý ủy quyền sẵn sàng xử lý đăng nhập.

Login chỉ được thực hiện qua phương thức Login của authorization manager, ví dụ từ một hàm REST mới. Hoặc kbmMW có thể tự động phát hiện login và gọi Login nếu bạn đặt thuộc tính Options của manager thành [mwaoAutoLogin].

Khi kbmMW phát hiện token không hợp lệ hoặc không tồn tại, nó ném ngoại lệ EkbmMWAuthException. Đối với REST, ngoại lệ này được chuyển thành HTTP 401 (Unauthorized) – thông báo cho client. Bạn cũng có thể tự ném ngoại lệ này trong code nghiệp vụ để buộc trả về 401.

Bây giờ, hãy xác định resource. Đối với REST, thường là các phương thức. Sử dụng attribute kbmMW_Auth trong smart service để khai báo.

Ví dụ (Unit8):

[kbmMW_Service('name:MyREST, flags:[listed]')]
[kbmMW_Rest('path:/MyREST')]
TkbmMWCustomSmartService8 = class(TkbmMWCustomSmartService)
 public
  [kbmMW_Auth('role:[READER,READWRITER], grant:true')]
  [kbmMW_Rest('method:get, path:helloworld, anonymousResult:true')]
  [kbmMW_Method]
  function HelloWorld:TMyResult;

  [kbmMW_Auth('role:[READER,READWRITER], grant:true')]
  [kbmMW_Rest('method:get, path:contacts, anonymousResult:true')]
  function GetContacts:TObjectList;

  [kbmMW_Auth('role:[READWRITER], grant:true')]
  [kbmMW_Rest('method:put, path:addcontact')]
  function AddContact([kbmMW_Rest('value:"{$name}"')] const AName:string;
    [kbmMW_Rest('value:"{$address}"')] const AAddress:string;
    [kbmMW_Rest('value:"{$zipcode}"')] const AZipCode:string;
    [kbmMW_Rest('value:"{$city}"')] const ACity:string):string; overload;

  [kbmMW_Auth('role:[READWRITER], grant:true')]
  [kbmMW_Rest('method:get, path:"addcontact/{name}"')]
  function AddContact([kbmMW_Rest('value:"{name}"')] const AName:string):string; overload;

  [kbmMW_Auth('role:[READWRITER], grant:true')]
  [kbmMW_Rest('method:delete, path:"contact/{id}"')]
  function DeleteContact([kbmMW_Rest('value:"{id}"')] const AID:string):boolean;
 end;

kbmMW tự động đặt tên resource cho các hàm này, ví dụ: MyREST..AddContact, MyREST..GetContacts, v.v. Nếu service có version, tên resource sẽ có thêm dấu chấm giữa.

Bạn cũng có thể kiểm tra ủy quyền thủ công, chi tiết hơn:

var
  res: TkbmMWAuthorizationStatus;
  sMessage: string;
begin
  res := AuthorizationManager1.IsAuthorized(logintoken, 'YOURRESOURCENAME', sMessage);

Giá trị trả về: mwasAuthorized, mwasNotAuthorized, hoặc mwasConstrained (ủy quyền có thể được cấp trong điều kiện khác).

Trong smart service, bạn có thể lấy login token như một tham số:

 [kbmMW_Auth('role:[READER], grant:true')]
 [kbmMW_Rest('method:get, path:"someCall"')]
 function SomeCall([kbmMW_Arg(mwatToken)] const AToken:string):boolean;

Hoặc thông qua thuộc tính ClientIdentity.Token bên trong phương thức.

Bây giờ REST server của bạn đã được bảo vệ với SSL và quản lý truy cập qua login.

Để tìm hiểu thêm, tham khảo tài liệu kbmMW tại components4developers.com.

Thẻ: kbmMW REST AuthorizationManager AccessControl Delphi

Đăng vào ngày 4 tháng 6 lúc 21:31