Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> Ruby

Nắm vững ủy quyền Ruby:Pundit so với CanCanCan

Ngày nay, nhiều ứng dụng web sẽ có các trang được cung cấp công khai — như trang chủ — và các trang an toàn hơn nơi người dùng phải đăng nhập để có quyền truy cập. Quá trình đăng ký người dùng, đăng nhập và theo dõi trạng thái phiên người dùng được gọi là "xác thực".

Đồng thời, khi xử lý người dùng đã đăng nhập, cần tách biệt các hành động và tài nguyên có sẵn cho họ tùy thuộc vào vai trò người dùng của họ. Ví dụ:"quản trị viên" thường có nhiều quyền truy cập hơn người dùng bình thường. Quá trình tách quyền truy cập của người dùng được xác thực này được gọi là "ủy quyền".

Trong bài đăng này, chúng ta sẽ khám phá hai thư viện ủy quyền phổ biến nhất trong Ruby cho đến nay:Pundit và CanCanCan.

Hãy cùng đi sâu vào!

Thiết lập và điều kiện tiên quyết

Trong bài viết này, chúng tôi sẽ sử dụng một ứng dụng Rails 7 đơn giản có người dùng và bài đăng. Người dùng sẽ được giao vai trò "biên tập viên" hoặc "người viết". Kịch bản như vậy là hoàn hảo để thể hiện cách thức hoạt động của ủy quyền.

Hãy xem kho mã cho ứng dụng mẫu của chúng tôi bằng:

  • Nhà học giả
  • CanCanCan

Mặc dù bài viết này tập trung vào ủy quyền nhưng không thể bỏ qua chủ đề xác thực đồng hành.

Chúng tôi sẽ không đi sâu vào chi tiết thiết lập xác thực vì điều đó nằm ngoài phạm vi của bài đăng này. Bạn có thể làm theo hướng dẫn cài đặt trong tài liệu đá quý Devise (chúng tôi sẽ ghép nối Devise với đá quý ủy quyền của chúng tôi).

Một điều nữa — cho dù bạn làm việc với Pundit hay CanCanCan, công việc thực tế trong việc xác định vai trò người dùng trong ứng dụng của bạn sẽ không tự động diễn ra khi bạn cài đặt một trong hai viên ngọc ủy quyền. Bạn sẽ cần phải thiết lập thủ công.

Hãy làm điều đó.

Xác định vai trò của người dùng

Giả sử bạn đã cài đặt gem Devise và thiết lập mô hình người dùng. Bước tiếp theo là quyết định vai trò của người dùng ứng dụng. Trong trường hợp của chúng tôi, chúng tôi sẽ đặt ra các vai trò sau:

  • Nhà văn - Vai trò người dùng này sẽ có thể tạo , chỉnh sửa , cập nhậtxóa bài viết của riêng họ. Đồng thời, người viết cũng có thể xem bài viết của các nhà văn khác.
  • Biên tập viên - Người dùng có vai trò biên tập viên có thể chỉnh sửa , cập nhật , xemxóa bất kỳ bài đăng nào của người dùng nhưng họ không thể tạo bài viết của riêng họ.

Thêm một cột để lưu trữ vai trò của người dùng (sử dụng di chuyển để sửa đổi bảng của người dùng):

 

Sau đó chạy di chuyển:

 

Sau đó sửa đổi mô hình người dùng để bao gồm các vai trò chúng ta vừa xác định:

 

Trong khi chúng ta đang thực hiện việc này, hãy tiếp tục và thiết lập Post mô hình với thuộc tính titlebody , cũng như tham chiếu đến người viết bài đăng:

 

Chúng tôi thêm khóa ngoại user_id vào Post mô hình để liên kết mọi bài đăng được tạo với một người dùng cụ thể. Vì chúng ta đã thiết lập xác thực người dùng bằng Devise nên chúng ta chỉ cần sửa đổi phương thức tạo của Posts bộ điều khiển để tự động đặt user_id tới người dùng hiện đang đăng nhập:

 

Chúng tôi cũng có thể sửa đổi mô hình Người dùng để đảm bảo mô hình đó được liên kết với Post người mẫu:

 

Cuối cùng, hãy chọn một số người dùng vào cơ sở dữ liệu, mỗi người có một vai trò khác nhau:

 

Sau đó chọn cơ sở dữ liệu:

 

Cho đến nay, ứng dụng của chúng tôi hiện có:

  • Thiết lập xác thực bằng Devise.
  • Hai vai trò người dùng được xác định là "người viết" và "người biên tập".
  • A Post người mẫu.

Cùng với đó, giờ đây chúng tôi có mọi thứ cần thiết để hoạt động bình thường với Pundit.

Ủy quyền trong ứng dụng Ruby của bạn với Pundit

Pundit là một thư viện ủy quyền được xây dựng dựa trên kiến trúc hướng đối tượng và các lớp Ruby đơn giản. Nó cung cấp cho bạn các công cụ để xây dựng một lớp ủy quyền vững chắc có thể mở rộng quy mô theo ứng dụng của bạn.

Cài đặt Pundit trong ứng dụng Ruby của bạn

Thêm đá quý vào Gemfile của ứng dụng của bạn:

 

Sau đó trong terminal, chạy lệnh:

 

Ngoài ra, hãy chạy lệnh sau:

 

Vì việc ủy quyền chủ yếu liên quan đến việc cấp hoặc từ chối quyền truy cập vào tài nguyên của bộ điều khiển nên bước tiếp theo là thêm mô-đun ủy quyền của Pundit vào bộ điều khiển ứng dụng:

 

Và cuối cùng, tạo một lớp chính sách cơ sở, tất cả các chính sách khác sẽ kế thừa từ:

 

Cung cấp cho bạn lớp chính sách cơ bản sau:

 

Cùng với đó, Pundit hiện đã được thiết lập đúng cách và sẵn sàng hoạt động. Ngoài ra, chúng tôi còn thiết lập xác thực và vai trò người dùng.

Tiếp theo, hãy sử dụng các chính sách để triển khai các quy tắc xác định cách mỗi vai trò người dùng sẽ truy cập vào Post tài nguyên.

Định cấu hình chính sách của chuyên gia

Trong biệt ngữ Pundit, "chính sách" là một lớp Ruby đơn giản nơi bạn xác định tất cả các quy tắc về cách vai trò người dùng tương tác với các tài nguyên khác nhau.

Các chính sách này có một số tính năng đáng chú ý:

  • Mỗi chính sách được đặt tên theo một mô hình hiện có, có hậu tố là từ "Chính sách". Ví dụ:chính sách xác định cách Post mô hình được truy cập được gọi là PostPolicy .
  • Một attr_reader :điều này cần hai đối số - đối số đầu tiên là user , cụ thể là người dùng hiện đang đăng nhập — current_user — và đối số thứ hai là mô hình mà bạn muốn xác định quy tắc ủy quyền, trong trường hợp của chúng tôi là post .
  • Các phương thức truy vấn sẽ ánh xạ tới các phương thức điều khiển của tài nguyên đã thiết lập quy tắc ủy quyền. Vì mục đích tổ chức, tốt nhất nên có tất cả các chính sách theo app/policies thư mục.

Vì chúng ta biết những quy tắc truy cập nào cần xác định cho các vai trò người dùng khác nhau trong ứng dụng của mình nên hãy bắt đầu với vai trò người viết.

Xác định chính sách chuyên gia cho vai trò

Hãy sử dụng vai trò nhà văn để xem điều này có thể được thực hiện như thế nào. Để bắt đầu, chúng ta có thể phác thảo quyền truy cập của vai trò người viết vào Post tài nguyên như sau:

  • Tạo bài đăng của chính họ
  • Chỉnh sửa và cập nhật bài đăng của chính họ
  • Xem (hoặc đọc) bài đăng của chính họ cũng như bài đăng của người dùng khác
  • Xóa bài đăng của chính họ

Với ý nghĩ đó, hãy tiếp tục và tạo chính sách mới để kiểm soát cách truy cập bài đăng:

 

Điều này cung cấp cho chúng tôi lớp chính sách chung sau đây kế thừa từ chính sách cơ sở mà chúng tôi đã tạo trước đó:

 

Bây giờ, hãy thêm các quy tắc truy cập cho vai trò người viết tương ứng (các quy tắc này cũng ghi đè bất kỳ quy tắc nào được kế thừa từ lớp chính sách cơ sở):

 

Ở đây, chúng tôi xác định những gì người viết có thể làm khi tạo, chỉnh sửa, cập nhật và xóa các bài đăng là những hành động tương ứng trên bộ điều khiển của bài đăng. Nếu bạn để ý, những quy tắc này áp dụng cho các bài đăng nói chung và không nhất thiết áp dụng cho các bài đăng của chính người viết (chúng ta sẽ đề cập đến vấn đề đó trong phần về phạm vi).

Bây giờ, hãy xem cách chúng tôi có thể sử dụng chính sách này.

Sử dụng chính sách trong Pundit

Để sử dụng chính sách, hãy gọi tới authorize của Pundit trên phương thức của bộ điều khiển nơi bạn muốn kiểm tra quy tắc truy cập. Bạn khởi tạo lớp chính sách có liên quan và cụ thể hơn là hành động sẽ được gọi dựa trên vị trí authorize phương thức đã được gọi.

Ví dụ:hãy gọi authorize trên tạo của người điều khiển bài đăng phương pháp:

 

Để kiểm tra điều này, hãy đăng nhập với tư cách là biên tập viên và thử create một bài viết. Làm điều này sẽ dẫn đến lỗi sau:

Nắm vững ủy quyền Ruby:Pundit so với CanCanCan

Mặc dù điều này thực hiện được những gì chúng tôi muốn nhưng việc hiển thị một trang lỗi như vậy không tốt cho trải nghiệm người dùng. Trong phần tiếp theo, bạn sẽ tìm hiểu cách giải cứu NotAuthorizedError và cung cấp thứ gì đó thân thiện hơn với người dùng.

Giải cứu khỏi NotAuthorizedError của Pundit

Trước tiên, chúng ta cần chỉnh sửa ApplicationController như sau:

 

Ở đây, về cơ bản chúng tôi đang yêu cầu Pundit sử dụng user_not_authorized phương thức bất cứ khi nào NotAuthorizedError được nâng lên. Nó sẽ chỉ chuyển hướng người dùng trái phép đến một trang cụ thể và cũng cung cấp một thông báo flash có liên quan giải thích điều gì đã xảy ra:

Nắm vững ủy quyền Ruby:Pundit so với CanCanCan

Bây giờ chúng tôi có một hệ thống ủy quyền đơn giản có khả năng xử lý các trường hợp cấp quyền rất tổng quát.

Nhưng nếu chúng ta muốn có nhiều quyền chi tiết hơn thì sao? Để làm được điều này, chúng ta cần tận dụng phạm vi của Pundit.

Phạm vi của chuyên gia

Phạm vi Pundit tương tự như phạm vi ActiveRecord. Sau này, bạn có thể sử dụng phạm vi để tìm nạp các bản ghi theo tiêu chí cụ thể. Tuy nhiên, với phạm vi của Pundit, bạn quản lý quyền truy cập vào các tài nguyên cụ thể theo các quy tắc nhất định mà bạn đặt ra.

Giả sử chúng tôi muốn người chỉnh sửa có thể xem và chỉnh sửa các bài đăng ở trạng thái "bản nháp", đồng thời cho phép người viết tạo, xem, chỉnh sửa, cập nhật và xóa các bài đăng chỉ thuộc về họ.

Chúng ta có thể bắt đầu bằng cách chỉnh sửa chính sách bài đăng như thế này:

 

Sau đó, chúng tôi sẽ cấp quyền truy cập vào tài nguyên trong bộ điều khiển bài đăng, như vậy:

 

Tất nhiên, việc xác định phạm vi với Pundit có thể đi sâu hơn nhiều so với những gì chúng tôi đã trình bày, nhưng chúng tôi sẽ dừng lại ở đó trong bài viết này. Nếu muốn, hãy xem tài liệu của Pundit để biết cách bạn có thể sử dụng phạm vi theo cách nâng cao hơn.

Bây giờ, hãy xem cách bạn có thể sử dụng thư viện với các tham số mạnh của Rails.

Sử dụng Pundit với tham số mạnh của Rails

Bằng cách kết hợp các quy tắc ủy quyền của Pundit với các tham số mạnh của Rails, bạn có thể đạt được quyền truy cập khóa vào các thuộc tính của tài nguyên. Giả sử bạn muốn biên tập viên là những người duy nhất có quyền truy cập vào trường trích đoạn của Post mô hình. Bạn sẽ giải quyết việc đó như thế nào?

Đầu tiên, thêm một khối được đặt tên phù hợp vào chính sách liên quan:

 

Sau đó, sửa đổi khối thông số được phép trong bộ điều khiển:

 

Với điều đó, bạn đã thực hiện được đoạn trích thuộc tính chỉ dành cho người chỉnh sửa.

Bây giờ chúng ta sẽ chuyển sang xem thư viện ủy quyền khác, CanCanCan.

Giới thiệu CanCanCan cho ứng dụng Ruby của bạn

CanCanCan là thư viện ủy quyền sử dụng lớp "khả năng" để xác định ai có quyền truy cập vào nội dung trong ứng dụng Rails. Kiểm soát quyền truy cập thực tế đạt được bằng cách sử dụng mô-đun ủy quyền và nhiều trình trợ giúp chế độ xem khác nhau.

Cài đặt CanCanCan

Việc cài đặt dễ dàng như chạy lệnh bên dưới:

 

Giống như Pundit, với CanCanCan, bạn có thể xác định tất cả các quy tắc truy cập trong một đối tượng lớp Ruby đơn giản được gọi là lớp "khả năng". Hãy thực hiện điều đó tiếp theo bằng lệnh tạo sau:

 

Cái nào tạo ra đối tượng lớp bên dưới:

 

Tiếp theo, hãy tìm hiểu thêm về cách lớp khả năng có thể xác định quy tắc truy cập cho ứng dụng Rails mẫu của chúng tôi.

Xác định và kiểm tra khả năng của CanCanCan

Chúng ta sẽ sử dụng các vai trò người dùng giống như trong ví dụ về Pundit:người viết và người biên tập. Người viết có thể tạo, chỉnh sửa, cập nhật, hủy bài đăng của chính họ và xem bài đăng của người viết khác; biên tập viên có thể làm mọi thứ ngoại trừ việc tạo bài đăng của riêng họ.

Để sử dụng CanCanCan, trước tiên hãy xác định nội dung mà mỗi người dùng hoặc vai trò có thể truy cập trong lớp khả năng, theo định dạng sau:

 

Ví dụ:

 

Sau đó, trong bộ điều khiển, hãy kiểm tra xem quy tắc truy cập có tồn tại cho một hành động cụ thể hay không — sử dụng ví dụ của chúng tôi, edit hành động:

 

Với điều này, nếu chúng tôi truy cập chế độ xem chỉnh sửa bài đăng với tư cách là một người viết khác, chúng tôi sẽ gặp lỗi bên dưới:

Nắm vững ủy quyền Ruby:Pundit so với CanCanCan

Và giống như chúng ta đã làm với Pundit, hãy khắc phục lỗi này và hiển thị cho người dùng một trang lỗi tốt hơn.

Xử lý lỗi “Truy cập bị từ chối” của CanCanCan

Bất cứ khi nào tài nguyên không được ủy quyền, CanCanCan sẽ đưa ra CanCan::AccessDenied lỗi. Cách dễ nhất để nắm bắt ngoại lệ này là sửa đổi ApplicationController như sau:

 

Việc làm này mang lại trải nghiệm tốt cho người dùng. Trong ảnh chụp màn hình bên dưới, người dùng trái phép được chuyển hướng đến trang chủ và hiển thị thông báo flash có liên quan:

Nắm vững ủy quyền Ruby:Pundit so với CanCanCan

Bạn thậm chí có thể tùy chỉnh thông báo lỗi hiển thị cho người dùng:

 

Nếu ứng dụng của bạn phân phát XML dưới dạng phản hồi hoặc bạn chỉ muốn tìm hiểu sâu hơn về cách xử lý CanCanCan::AccessDenied ngoại lệ, hãy xem tài liệu của CanCanCan. Bây giờ, hãy xem cách chúng ta có thể kết hợp các khả năng khác nhau của CanCanCan để tạo ra lớp ủy quyền mạnh mẽ hơn.

Kết hợp nhiều khả năng của CanCanCan

Bạn có thể xác định nhiều quy tắc truy cập cho một tài nguyên trong lớp khả năng. Ví dụ:lấy vai trò người viết và biên tập viên, chúng ta có thể làm điều này:

 

Câu hỏi đặt ra là tại sao bạn lại muốn làm điều này?

Với CanCanCan, bạn có thể xác định tất cả các quy tắc truy cập trong một tệp khả năng. Điều này có cả ưu điểm và nhược điểm.

Việc có tất cả các quy tắc của bạn ở một nơi sẽ rất thuận tiện cho việc xử lý các quy tắc truy cập vì tất cả các quy tắc đều được xác định ở một nơi.

Tuy nhiên, nếu ứng dụng của bạn xử lý nhiều vai trò người dùng hoặc bạn có một số tài nguyên cần được ủy quyền thì lớp khả năng có thể dễ dàng trở nên quá lớn và phức tạp để xử lý. Một cách để giải quyết vấn đề này là tổ chức lại lớp khả năng để sử dụng các định nghĩa phương thức, như sau:

 

CanCanCan còn nhiều điều hơn thế nữa mà bài viết này có thể trình bày một cách hiệu quả. Hãy xem tài liệu chi tiết của CanCanCan để tìm hiểu thêm.

Để kết thúc, chúng ta hãy điểm qua ngắn gọn các tính năng của từng thư viện và đưa ra lý do tại sao bạn có thể chọn thư viện này mà không phải thư viện kia.

So sánh tính năng:Pundit và CanCanCan cho ứng dụng Ruby của bạn

  • Tổ chức tệp - Với Pundit, bạn có thể dễ dàng sắp xếp ủy quyền ứng dụng của mình trên nhiều tệp chính sách. Nhưng với CanCanCan, các quy tắc ủy quyền sẽ tồn tại trong một tệp khả năng. Bạn vẫn có thể làm việc với nhiều tệp khả năng nhưng đây không phải là kiểu triển khai mặc định.
  • Thử nghiệm - Bởi vì mã quyền hầu hết sẽ nằm trong một lớp duy nhất so với nhiều lớp khả năng của Pundit, nên việc viết bài kiểm tra cho CanCanCan có thể dễ dàng hơn so với Pundit.
  • Người trợ giúp - Cả hai thư viện đều cung cấp một số trình trợ giúp chế độ xem để kiểm tra các quyền trong lớp chế độ xem. CanCanCan mang đến cho bạn can? để sử dụng trong chế độ xem của bạn, trong khi Pundit cung cấp cho bạn chức năng tương đối giống với policy người trợ giúp.
  • Đưa ra giải pháp tích hợp - Như bạn có thể thấy từ các ví dụ chúng tôi đã sử dụng trong bài viết, cả hai thư viện đều tích hợp rất tốt với Devise.

Kết thúc

Trong bài viết này, chúng ta đã xem xét hai trong số những loại gem ủy quyền phổ biến nhất trong hệ sinh thái Ruby và Rails:Pundit và CanCanCan.

Cả hai thư viện đều cung cấp một bộ tính năng phong phú để quản lý quyền trong ứng dụng Rails của bạn. Do đó, gần như không thể cho bạn biết nên chọn loại ngọc nào — cả hai đều có thể quản lý ngay cả những thiết lập quyền phức tạp nhất.

Chúng tôi khuyến khích bạn dùng thử Pundit và CanCanCan trong ứng dụng của mình và xem ứng dụng nào phù hợp với nhu cầu của bạn nhất.

Chúc bạn viết mã vui vẻ!

Tái bút. Nếu bạn muốn đọc các bài đăng của Ruby Magic ngay khi chúng được đăng tải, hãy đăng ký nhận bản tin Ruby Magic của chúng tôi và không bao giờ bỏ lỡ một bài đăng nào!