Tìm hiểu về gem cancancan

Nếu bạn xây dựng một ứng dụng với nhiều loại user và điều bạn lo lắng nhất chính là phân quyền cho các user của bạn. Một giải pháp hiệu quả cho bạn đó là sử dụng gem Cancancan để phân quyền cho các user

Cancancan là một thư viện phân quyền cho ruby on rails, nó hạn chế các tài nguyên mà một user được phép truy cập. Tất cả các quyền hạn được quy định ở một nơi duy nhất (là class Ability) và riêng biệt với controllers, views và database queries

1. Cài đặt

Với rails 3 và 4, bạn thêm vào Gemfile dòng sau, sau đó chạy lệnh bundle install

	gem 'cancancan', '~> 1.10'

2. Bắt đầu với Cancancan

2.1. Định nghĩa Abilities:

Phân quyền User được định nghĩa trong class Ability. Cancan 1.5 gồm có 1 bộ tạo rails 3 và 4 để tạo ra class này

	rails g cancan:ability

Trong rails 2.3, chỉ cần thêm một class mới trong app/models/ability.rb với nội dung như sau

    class Ability
      include CanCan::Ability

      def initialize(user)
      end
    end

Ví dụ

	class Ability
      include CanCan::Ability

      def initialize(user)
        user ||= User.new # guest user (not logged in)
        if user.admin?
          can :manage, :all
        else
          can :read, :all
        end
      end
    end

Các model người dùng hiện thời được cho vào phương thức initialize, vì vậy việc phân quyền có thể được thay đổi dựa trên bất kỳ các thuộc tính của user

Phương thức can:

Phương thức can được sử dụng để định nghĩa việc phân quyền và yêu cầu 2 tham số. Đầu tiên là action mà bạn đang thiết lập phân quyền cho, thứ 2 là calss của đối tượng mà bạn muốn thiết lập action đó cho nó

	can :update, Article

Bạn có thể đặt :manage để đại diện cho bất kỳ hành động nào và :all đại diện cho bất kỳ đối tượng nào

    can :manage, Article  # user can perform any action on the article
    can :read, :all       # user can read any object
    can :manage, :all     # user can perform any action on any object

Bạn có thể nhập 1 mảng các tham số. Ví dụ, user sẽ có khả năng update và destroy cả articles và comments

	can [:update, :destroy], [Article, Comment]

2.2. Kiểm tra Ability và phân quyền:

Sau khi định nghĩa Ability, bạn có thể sử dụng phương thức can?cannot? trong view và controller để kiểm tra quyền của user cho action và object

    <% if can? :update, @article %>
      <%= link_to "Edit", edit_article_path(@article) %>
    <% end %>

Phương thức cannot? thì đối lập với phương thức can?

Phương thức authorize! trong controller sẽ đưa ra một ngoại lệ nếu user không có khả năng để thực hiện hành động đó

    def show
      @article = Article.find(params[:id])
      authorize! :read, @article
    end

Hay bạn có thể sử dụng phương thức load_and_authorize_resource để cung cấp ủy quyền tự động cho tất cả các hành động trong RESTfull. Nó sẽ sử dụng bộ lọc trước để load tài nguyên vào một biến instance và cho phép nó mọi hành động

    class ArticlesController < ApplicationController
      load_and_authorize_resource

      def show
        # @article is already loaded and authorized
      end
    end

Strong Parameters:

khi sử dụng strong_parameters hoặc Rails 4+, bạn có làm sạch đầu ra trước khi lưu bản ghi trong các action như :create:update

Ngoài ra, load_and_authorize_resource có thể chọn lựa lấy param_method để xác định một phương thức tùy ý trong controller để chạy

Bạn có thể liên kết lựa chọn param_method với một ký tự tương ứng với tên của phương thức mà sẽ được gọi

    class ArticlesController < ApplicationController
      load_and_authorize_resource param_method: :my_sanitizer

      def create
        if @article.save
          # hurray
        else
          render :new
        end
      end

      private

      def my_sanitizer
        params.require(:article).permit(:name)
      end
    end

Bạn cũng có thể sử dung một string, nó sẽ được đánh giá trong khuôn khổ controller đang sử dụng instance_eval và cần phải chứa code Ruby phù hợp

    load_and_authorize_resource param_method: 'permitted_params.article'

Cuối cùng, nó có thể liên kết param_method với một đối tượng Proc được gọi bởi controller như một đối số duy nhất

	load_and_authorize_resource param_method: Proc.new { |c| c.params.require(:article).permit(:name) }

2.3. Xử lý các truy cập trái phép:

Nếu việc cấp phép user thất bại, một ngoại lệ CanCan::AccessDenied sẽ được sinh ra. Bạn có thể bắt lấy và thay đổi hành vi của nó trong ApplicationController

    class ApplicationController < ActionController::Base
      rescue_from CanCan::AccessDenied do |exception|
        redirect_to root_url, :alert => exception.message
      end
    end

2.4. Lock It Down:

Nếu bạn muốn đảm bảo chắc chắn việc cấp phép xẩy ra trên mọi action trong ứng dụng của bạn, hãy thêm vào check_authorization vào ApplicationContronller

    class ApplicationController < ActionController::Base
      check_authorization
    end

Điều này sẽ sinh ra một ngoại lệ nếu việc ủy quyền không được thực hiện trong một action. Nếu bạn muốn bỏ qua việc này thì thêm skip_authorization_check vào một lớp con controller

Kết luận

Nhờ có gem Cancan mà việc phân quyền cho các user trở nên đơn giản và dễ dàng hơn rất nhiều, giúp ích rất nhiều cho ứng dụng của bạn. Kiến thức còn hạn hẹp và nhiều thiếu sót, rất mong sự góp ý của bạn đọc. Rất cảm ơn bạn đã theo dõi bài viết của tôi. Mong rằng nó sẽ giúp ích cho bạn đc phần nào đó. Xin chân thành cảm ơn!

tài liệu tham khảo: https://github.com/CanCanCommunity/cancancan