Права доступа и CanCan

CanCan - это гем, который используется для разграничений прав доступа. Для того, чтобы установить его добавьте в ваш Gemfile запись: gem "cancan" и выполните bundle install. После этого создайте файл с привилегиями выполнив...

Автор . Дата: 01.11.2014

CanCan - это гем, который используется для разграничений прав доступа. Для того, чтобы установить его добавьте в ваш Gemfile запись:

gem "cancan"

и выполните bundle install. После этого создайте файл с привилегиями выполнив:

rails g cancan:ability

Сгенерируется файл Ability.rb, который будет лежать в папке с вашими моделями.

CanCan использует метод current_user для получения текущего пользователя, который находится в системе. Это сделано для совместимости с другими гемами, такие как Authlogic или Devise. Если вы хотите написать аутентификацию сами, то вам нужно будет обязательно написать метод current_user (например в каком-нибудь хелпере), который будет возвращать текущего пользователя.

Привилегии

can метод используется для объявления прав доступа и требует два аргумента. Первый аргумент это экшен, к которому вы хотите дать доступ пользователю, второй это класс или объект для которого вы устанавливаете права доступа:

can :manage, Article  # пользователь может делать все действия с моделью Article
can :read, :all       # пользователь может читать все что угодно
can :manage, :all     # пользователь может производить все действия с чем угодно

Пример файла Ability.rb:

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

Вы можете использовать любые экшены из GRUD набора, или свои собственные. Так же можно описывать несколько экшенов и моделей разом:

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

Проверка привилегий

Текущие права пользователя можно проверить используя метода can? и cannot? во вьюхах и контроллерах:

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

Ссылка будет отображена только если у текущего пользователя есть права для работы с экшеном update объекта @article

Но просто скрыть ссылку недостаточно. Умный пользователь может вручную сформировать URL и получить доступ к тому, чему не должен. На этот случай есть методы в контроллеры, для второго уровня проверок.

Метод authorize! используется в контроллерах для того, чтобы вызвать исключение, если у пользователя нет прав. Пример:

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

Будет вызвано исключение, если пользователь не может использовать экшен read для объекта @article. Обрабатывать исключения можно с помощью следующего кода:

rescue_from CanCan::AccessDenied do |exception|
  redirect_to root_path, :alert => { msg: I18n.t('info.cant_access'), :class => 'alert-danger' }
end

Его следует добавить в application_controller.rb. При появлении исключения пользователь будет редиректнут по маршруту root_path с выводом соответствующих сообщений.

Но добавление authorize! в каждый экшен контроллера может быстро надоесть, поэтому на этот случай есть метод load_and_authorize_resource. Он выполняет все теже действия что и authorize! но при этом его достаточно объявить всего один раз в начале контроллера. Но обрабатывает экшены он только для GRUD модели, т.е. для своих каких-то экшенов вам нужно будет использовать authorize! Пример:

class ArticlesController < ApplicationController
  load_and_authorize_resource

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

Эта статья только первая в цикле. Cancan имеет огромное множество возможностей и багов, все их освятить в одной статье явно не получится. В следующей статье мы подробно рассмотрим настройку привилегий.