Authorizing your Rails app with Authority and Rolify
Bài viết này mình xin giới tiệu 1 cách phân quyền mới mạnh mẽ và có thể sử dụng linh hoạt bằng cách sử dụng : Devise: Cung cấp chứng thực(authentication): cho phép người dùng đăng kí và đăng nhập, để bạn biết họ là ai. Rolify: Giúp bạn chỉ định vai trò ...
Bài viết này mình xin giới tiệu 1 cách phân quyền mới mạnh mẽ và có thể sử dụng linh hoạt bằng cách sử dụng :
- Devise: Cung cấp chứng thực(authentication): cho phép người dùng đăng kí và đăng nhập, để bạn biết họ là ai.
- Rolify: Giúp bạn chỉ định vai trò cho người dùng và kiểm tra vai trò mà họ có.
- Authority: Điều khiển các role quản lí chúng sao cho phù hợp. Giúp bạn sử dụng các role hoặc bất kỳ logic nào bạn thích) để kiểm soát ai có thể làm những gì.
Ta thêm 3 gem vào trong gemfile rồi install:
gem 'devise' gem 'authority' gem 'rolify'
Bước 1: Cài đặt devise cho user
rails generate devise:install rails generate devise User
Bước 2: Cài đặt gem Authority
rails generate authority:install
Bước 3: Cài đặt gem Rolify
rails generate rolify:role
Sau đó rake db:migrate ta được 2 model: 1 model chứa các role, và 1 model quản lý role của user
Sau khi cài đặt, ta có được file /config/initializers/authority.rb chứa định nghĩa các quyền
Authority.configure do |config| // Định nghĩa các quyền tương ứng với các action trong controler. Bạn có thể tùy chỉnh theo cách bạn muốn. Mặc định là: config.controller_action_map = { :index => 'read', :show => 'read', :new => 'create', :create => 'create', :edit => 'update', :update => 'update', :destroy => 'delete' } // Định nghĩa các abiliies config.abilities = { :create => 'creatable', :read => 'readable', :update => 'updatable', :delete => 'deletable' } //user ta dùng để sử dụng để phân quyền. có thể là current_user hoặc current_admin config.user_method = :current_user end
Chỉnh sửa ApplicationAuthorizer được tạo mặc định khi cài gem authority. cập nhập default method để check xem có role admin không?
def self.default(adjective, user) user.has_role? :admin end
Điều này cho thấy rằng tất cả các action đều yêu cầu vai trò role admin theo mặc định. Sau đó bạn có thể bắt đầu thêm logic cụ thể hơn.
# To update a specific resource instance, you must either own it or be an admin def updatable_by?(user) resource.author == user || user.has_role?(:admin) end
Sử dụng phương thức rolify's resourcify trên tất cả model bạn muốn thêm role cho nó. Ví dụ ta thêm role cho model Post
class Post < ActiveRecord::Base resourcify belongs_to :author, class_name: 'User' end
Thêm Authority::UserAbilities vào trong model uer(để thêm method như can_update?) và thêm Authority::Abilities vào trong model khác(để thêm method như updatable_by?)
class User < ActiveRecord::Base include Authority::UserAbilities has_many :posts, foreign_key: :author_id end ... class Post < ActiveRecord::Base resourcify include Authority::Abilities end
Ở controler ta tạo 1 authorizer định nghĩa quyền truy cập của user tại model User
class UserAuthorizer < ApplicationAuthorizer def self.updatable_by?(user) user.has_role?(:admin) || user.has_role?(:editor) end def self.creatable_by?(user) user.has_role?(:admin) || user.has_role?(:editor) end def self.readable_by?(user) user.has_role?(:admin) || user.has_role?(:editor) end def self.deletable_by?(user) user.has_role?(:admin) end end
Ở model /app/models/user.rb
class User < ActiveRecord::Base # creatable_by?(user) include Authority::Abilities # can_create?(resource) include Authority::UserAbilities # Tương ứng với /app/authorizers/user_authorizer.rb self.authorizer_name = 'UserAuthorizer' resourcify rolify after_create :assign_default_role def assign_default_role self.add_role(:editor) end # Include default devise modules. Others available are: # :confirmable, :lockable, :timeoutable and :omniauthable devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable#, :confirmable end
Ở controller: /app/controllers/admins/users_controller.rb
class Admins::UsersController < AdminsController alias :user_for_this_request :current_admins_user # ngoại trừ action show tất quả đều được phân quyền đã được định nghĩa ở user_authorizer.rb authorize_actions_for User, except: :show def index @users = User.all end def show end private # Use callbacks to share common setup or constraints between actions. def set_user @user = User.find(params[:id]) end # Never trust parameters from the scary internet, only allow the white list through. def user_params params .require(:user) .permit(:email, :password, :password_confirmation) end end
Ở application_controller ta render ra trang lỗi và báo với người dùng khi không có quyền truy cập
class ApplicationController < ActionController::Base rescue_from Authority::SecurityViolation, with: :authority_forbidden def authority_forbidden(error) Authority.logger.warn(error.message) render file: "#{Rails.root}/public/403.html", status: 403, layout: 'error' end end
Một vài câu lệnh hay dùng: Ta vào rails c . Tạo vài user bằng cách
> alice = User.new > alice.email = "alice@example.com" > alice.password = "test1234" > alice.save > bob = User.new > bob.email = "bob@example.com" > bob.password = "test1234" > bob.save > cathy = User.new > cathy.email = "cathy@example.com" > cathy.password = "test1234" > cathy.save
Thêm role admin cho user
> alice.add_role "admin"
Tạo Post cho user
> post = bob.posts.new > post.title = 'Test Post' > post.name = 'Test Post' > post.content = 'Nothing to see here' > post.save
Check xem ai có thể update Post
> bob.can_update?(post) #=> true; he is the author > alice.can_update?(post) #=> true; she is an admin > cathy.can_update?(post) #=> false
Kiếm tra xem user có role admin không
user.has_role? :admin #=> true or false
Xóa role admin của user
user.remove_role :admin
Hi vọng bài viết có thể giúp ích cho bạn!
Nguồn tham khảo:
http://qiita.com/keisukemizuno@github/items/9c079c275118fa7a0f36 https://github.com/RolifyCommunity/rolify/wiki/Using-rolify-with-Devise-and-Authority