權限控制[2] CanCan + Rolify + Devise

在model/ability.rb中定義權限

Reference: Defining Abilities
基礎權限

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

自定義權限集合

def initialize(user)
  user ||= User.new

  alias_action :create, :read, :update, :destroy, to: :crud

  can :crud, User
  can :invite, User
end

利用Hash條件篩選定義

class Photo
  has_and_belongs_to_many :groups
  scope :unowned, includes(:groups).where(groups: { id: nil })
end

class Group
  has_and_belongs_to_many :photos
end

class Ability
  def initialize(user)
    user ||= User.new # guest user (not logged in)
    can :read, Photo, Photo.unowned do |photo|
      photo.groups.empty?
    end
  end
end

利用代碼塊來定義權限

Reference: Defining Abilities with Blocks

can :update, Project do |project|
  project.priority < 3
end

重寫默認方法

Reference: Changing Defaults
利用cancancan+rolify+devise做權限控制,如果你使用的是自己建的表,名字有區別,可能會導致current_user無法正常使用。比方說,項目中的用戶表是buser,那麼用device之後,當前用戶就應該是current_buser,且需要重寫cancancan的默認加載方法。
直接把方法寫在ApplicaitonController中即可。

CanCanCan makes two assumptions about your application.

You have an Ability class which defines the permissions.
You have a current_user method in the controller which returns the current user model.
You can override both of these by defining the current_ability method in your ApplicationController. The current method looks like this.

def current_ability
  @current_ability ||= Ability.new(current_user)
end
The Ability class and current_user method can easily be changed to something else.

# in ApplicationController
def current_ability
  @current_ability ||= AccountAbility.new(current_account)
end

Restful Controller中的權限控制

Reference:
- Authorizing controller actions
- rails基於devise+cancancan+rolify的簡單權限控制實現
在controller中做權限控制,你可以控制整個controller,也可以逐個方法做局部控制。
針對有對應資源的controller,只需要在開頭加上控制語句即可。

You can use the authorize! method to manually handle authorization in a controller action. This will raise a CanCan::AccessDenied exception when the user does not have permission. See Exception Handling for how to react to this.

def show
  @project = Project.find(params[:project])
  authorize! :show, @project
end
However that can be tedious to apply to each action. Instead you can use the load_and_authorize_resource method in your controller to load the resource into an instance variable and authorize it automatically for every action in that controller.

class ProductsController < ActionController::Base
  load_and_authorize_resource
end
This is the same as calling load_resource and authorize_resource because they are two separate steps and you can choose to use one or the other.

class ProductsController < ActionController::Base
  load_resource
  authorize_resource
end

針對沒有對應資源的controller,我們也可以爲它指定需要加載的類。

class LogController < ApplicationControlle
    load_and_authorize_resource :class => "Production" 
     def record_log
        ........ 
     end

NonRestful Controller中的權限控制

Reference:Non RESTful Controllers
針對部分controller與資源不掛鉤的情況,我們也可以進行單獨控制。
注意,此時我們只能只能進行逐個方法的局部控制,不能統一控制controller。
在定義權限的時候,注意兩個參數必須都是ruby的符號對象。

For example, let's say we have a controller which does some miscellaneous administration tasks such as rolling log files. We can use the authorize! method here.

class AdminController < ActionController::Base
  def roll_logs
    authorize! :roll, :logs
    # roll the logs here
  end
end
And then authorize that in the Ability class.

can :roll, :logs if user.admin?
Notice you can pass a symbol as the second argument to both authorize! and can. It doesn't have to be a model class or instance. Generally the first argument is the "action" one is trying to perform and the second argument is the "subject" the action is being performed on. It can be anything.

頁面的權限控制

Reference:Checing Ablities
當我們在model/ablitiy.rb中定義完所有權限之後,我們可以在頁面上直接使用。

<% if can? :create, Project %>
  <%= link_to "New Project", new_project_path %>
<% end %>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章