+4

Một số options của CanCanCan

Cài đặt

Cách cài đặt gem CanCanCan rất đơn giản như mọi gem khác

  • gem 'cancancan'
  • bundle install

Cách sử dụng cơ bản

Giả sử trong project đã có các thành phần cơ bản. Mối user có đều role của họ.

  • Các quyền của user được định nghĩa trong file Ability.rb
  • Để tạo file này, chạy lệnh: rails g cancan:ability
  • Trong file này, để cho phép user truy cập vào tài nguyên, ta dùng hàm can để cho phép hoặc cannot để không cho phép.
class Ability
  include CanCan::Ability

  def initialize user
    can :read, [Product, Table]
    #user chưa đăng nhập có thể xem Product, Table
    return unless user
    # Nếu đăng nhập thì tiếp tục

    can [:show, :update], User, id: user.id
    # user nào thì xem và sửa profile của user đó
    case user.role
    when "admin"
      can :manage, :all
      # Admin có toàn quyền
    when "staff"
      can :manage, [Admin, OrderDetail, OrderTable, Order]
      # Staff có toàn quyền đối với trang admin dashboard, Order, OrderDetail, OrderTable
    when "guest"
      can :create, Order
      # Guest có thể tạo Order
    end
  end
end

  • Trong view hay trong controller, để kiểm tra quyền, ta dùng can? hoặc cannot?.
<% if can? :read, @order %>
  <%= link_to "View", @order %>
<% end %>
  • Để lấy về danh sách các bản ghi mà user có thể truy cập, ta có thể sử dụng hàm:
accessible_by(current_ability)
  • Tuy nhiên, để CanCanCan có thể hoạt động một cách chính xác, chúng ta cần phải kiểm tra quyền của user với các action trong controller. Để làm được như vậy, ta cần thêm authorize! vào mỗi action trong mỗi controller. Ví dụ trong orders_controller.rb:
def show
  @order = Order.find_by(id: params[:id]))
  authorize! :read, @order
end

Nhưng làm như vậy rất tốn công, vì thế CanCanCan có load_and_authorize_resource để hỗ trợ chúng ta authorize tất cả action theo chuẩn RESTful.

class UsersController < ApplicationController
  load_and_authorize_resource

  def show; end
end
  • Vậy, nếu user không có quyền truy cập vào tài nguyên thì chuyện gì sẽ xảy ra?
  • Khi đó exception CanCan::AccessDenied sẽ được tạo và ta sẽ xử lý nó trong ApplicationController.
rescue_from CanCan::AccessDenied do |exception|
    flash[:warning] = exception.message
    redirect_to root_url
  end

Vậy là ta đã phân quyền người dùng xong xuôi rồi, tiếp là một số cách để phân quyền trong một số trường hợp đặc biệt.

Một số options

1. Một số cách định nghĩa quyền của user.

  • Ngoài cách dùng các action theo RESTful để định nghĩa quyền cho user, chúng ta còn có thể định nghĩa các action khác.Ví dụ:

    Trong Ability.rb có:

can :asign_roles, User if user.admin?

Update role trong user_controller:

def update
  authorize! :assign_roles, @user if params[:user][:assign_roles]
  #..update roles
end
  • Ngoài ra, ta có thể tạo action alias để gộp nhiều action thành 1
alias_action :show, :index :to => :read
  • Ta có thể gán thêm điều kiện khi phân quyền:
can :read, Order, active: true, user_id: user.id
# chỉ user nào sở hữu order mới có thể đọc được order đó
can :read, Product, Category: { status: "enable" }
# chỉ có thể đọc được product nào mà category nó thuộc về còn "enable"

2. Tách Ability

  • Bên cạnh việc sử dụng class Ability để phân quyền, ta có thể tách các quyền có trong đó ra theo từng class khác nhau, có thể là tách theo model, tách theo controller.
  • Để tách được Ability thì ta cần ghi đè phương thức current_ability trong application_controller
def current_ability
  @current_ability ||= AccountAbility.new(current_account)
end

3. Bỏ qua phân quyền

  • Để có thể kiểm tra quyền mà không phải thêm hàm load_and_authorize_resource vào tất cả các controller thì thay vào đó, hãy thêm nó vào application_controller.
  • Nếu không cần kiểm tra quyền ở controller nào thì thêm skip_authorize_resource vào controller đó.

4. Kiểm tra việc phân quyền.

  • Nếu có một controller nào đó bị bỏ qua khi phân quyền, thì có thể thêm check_authorization vào application_controller.
  • Và nếu muốn bỏ qua việc check ở một controller nào đó thì thêm skip_authorization_check vào controller đó.

5. Lọc params

  • Nếu trong action như create, update chỉ có đơn thuần các lệnh tạo dữ liệu mà không có lệnh nào để lọc params, tránh các rủi ro khi params có dữ liệu xấu thì CanCanCan sẽ giúp ta lo việc đó.
class UsersController < ApplicationController
    def create
        if @user.save
          # hurray
        else
          render :new
        end
    end
end

CanCanCan có 4 cách để lọc params và ưu tiên theo thứ tự như sau:

  • Gọi hàm xử lý params theo tên action:
def create_params
  params.require(:user).permit(:name, :email)
end

def update_params
  params.require(:user).permit(:name)
end
  • Gọi hàm xử lý params theo tên model:
def user_params
  params.require(:user).permit(:name)
end
  • Gọi hàm resource_params:
def resource_params
    params.require(:user).permit(:name)
end
  • Gọi hàm xử lý params bất kì:
load_and_authorize_resource param_method: :my_params

def my_params
    params.require(:user).permit(:name)
end

Kết luận

Trên đây là một số cách để custom phân quyền với CanCanCan. Có rất nhiều options, nhưng không phải option nào cũng có hiệu quả với project của bản thân chúng ta. Vì vậy, chúng ta cần suy nghĩ kỹ, lựa chọn các options phù hợp với project của mình để áp dụng. Nếu không, việc phân quyền sẽ trở nên nặng nề, khiến project của chúng ta trở nên chậm chạp và có thể dẫn tới các sai sót không đáng có khác.

Nguồn: https://github.com/CanCanCommunity/cancancan/wiki


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí