Rails Authorization with Pundit
Bài đăng này đã không được cập nhật trong 9 năm
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!'
All rights reserved