Rails Authorization with Pundit
Xác thực người dùng và kiểm soát quyền của người dùng là phần quan trọng không thể thiếu. Một trong những gem xác thực thường được sử dụng trong RoR là Pundit. Pundit cung cấp một set helper cho phép bạn nâng tầm các class và các đối tượng trong Ruby để xây dựng một hệ thống xác thực đơn giản, hiểu ...
Xác thực người dùng và kiểm soát quyền của người dùng là phần quan trọng không thể thiếu. Một trong những gem xác thực thường được sử dụng trong RoR là Pundit. Pundit cung cấp một set helper cho phép bạn nâng tầm các class và các đối tượng trong Ruby để xây dựng một hệ thống xác thực đơn giản, hiểu qủa và dễ dàng nâng cấp.
I. Cài đặt:
gem "pundit"
Include Pundit trong application_controller.rb
class ApplicationController < ActionController::Base include Pundit protect_from_forgery end
Ngoài ra, bạn cũng có thể cài đặt các policy cơ bản bằng cách khởi tạo qua câu lệnh:
rails g pundit:install
II. Policy
Pundit tập trung vào các class policy và đặt trong app/policy. Sau đây là một ví dụ đơn giản, người dùng có thể cập nhập một bài viết (post) nếu có quyền admin hoặc nếu bài viết đó chưa được công khai (unpublished):
class PostPolicy attr_reader :user, :post def initialize(user, post) @user = user @post = post end def update? user.admin? or not post.published? end end
Như bạn thấy, đây là một class Ruby. Pundit sẽ đưa ra các gỉa định về class policy như sau:
- Class policy có cùng tên với class model, kèm theo hậu tố "Policy".
- argument đầu tiên là user. Trên controller, Pundit sẽ gọi current_user và gửi đến argument này.
- Argument thứ hai là một dạng object model, là object bạn cần xác thực. Object này không bắt buộc phải là một ActiveRecord hay là một object ActiveModel.
- Class sẽ implement một query method, ở ví dụ trên là method update?, tên method này tương ứng với một action trên controller.
III. Sử dụng các policy
Trên controller:
def update @post = Post.find(params[:id]) authorize @post if @post.update(post_params) redirect_to @post else render :edit end end
Trên view:
<% if policy(@post).update? %> <%= link_to "Edit post", edit_post_path(@post) %> <% end %>
IV. Báo lỗi NotAuthorizedErrors:
Pundit sẽ gọi Pundit::NotAuthorizedError trên ApplicationController. Pundit cho phép tùy biến method user_not_authorized cho tất cả các controller
class ApplicationController < ActionController::Base protect_from_forgery include Pundit rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized private def user_not_authorized flash[:alert] = "You are not authorized to perform this action." redirect_to(request.referrer || root_path) end end
Pundit cũng cho phép tùy biến báo lỗi cho từng method trong Policy. Người dùng có thể dùng các query, record, policy và I18n để tùy biến báo lỗi. Ví dụ như sau:
class ApplicationController < ActionController::Base rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized private def user_not_authorized(exception) policy_name = exception.policy.class.to_s.underscore flash[:error] = t "#{policy_name}.#{exception.query}", scope: "pundit", default: :default redirect_to(request.referrer || root_path) end end
Trên file I18n:
en: pundit: default: 'You cannot perform this action.' post_policy: update?: 'You cannot edit this post!' create?: 'You cannot create posts!'