Настройка модели CanCan Ability.rs

Я успешно создал систему входа в систему с помощью Devise и CanCan, и у меня есть 3 типа пользователей. Администратор, внутренние и глобальные пользователи. Я создал контроллеры и индексные действия: Admin, Cpanel, Report и State, и я хочу ограничить доступ к этим контроллерам для некоторых пользователей.

Пользователь-администратор должен иметь права доступа: Отчеты (все), Состояние (чтение), Администрирование (все).

Глобальный пользователь должен иметь права доступа: Отчеты (только чтение), Состояние (чтение), Cpanel (все)

Внутренний пользователь должен иметь права доступа: Отчеты (все), Состояние (чтение)

И я попытался сделать это с помощью следующего кода в файле Ability.rs:

class Ability
  include CanCan::Ability

  def initialize(user)
    user ||= User.new # guest user (not logged in)

    if user.role? :admin
      can :manage, [Report, Admin]
      can :read, State
    elsif user.role? :global_user
      can :read, [Report, State]
      can :manage, Cpanel
    elsif user.role? :internal_user
      can :manage, Report
      can :read, State     
    end
   end
end

В настоящее время у меня есть только действия индекса в этих контроллерах, и когда я вхожу в приложение с внутренним пользователем, я МОГУ получить доступ, например, к /admin, и это не то поведение, которое я хочу. Я хочу ограничить доступ ко всем контроллерам, а не к контроллерам, перечисленным в классе Ability.rb.

Исходный код находится здесь


person dormitkon    schedule 02.03.2011    source источник


Ответы (3)


Если бы я собирался запретить доступ ко всему контроллеру, я бы сделал перед фильтром, который перенаправляет пользователя на страницу с отказом в доступе, если у него нет роли администратора. Может выглядеть примерно так:

def check_permissions
 raise CanCan::AccessDenied unless @current_user.role?(:admin)
end

Если бы я просто хотел запретить доступ к обновлению и созданию, например, я бы сделал:

def update
  raise CanCan::AccessDenied unless can?(:update,Thing)
  ...
end

def create
  raise CanCan::AccessDenied unless can?(:create,Thing)
  ...
end

Вы можете обработать исключение CanCan::AccessDenied в контроллере вашего приложения:

rescue_from CanCan::AccessDenied do |exception|
    flash[:error] = exception.message
    redirect_to no_access_path
  end

У меня есть несколько довольно хороших сообщений о CanCan и Devise здесь и здесь

ОБНОВЛЕНИЕ Я использую этот метод в своем контроллере приложений, чтобы установить текущую пользовательскую переменную:

# Make the current user object available to views
  #----------------------------------------------------------------------------
  def get_user
    @current_user = session[:current_user]
  end
person Tony    schedule 02.03.2011
comment
Почему я получаю неопределенную роль метода? для нуля: NilClass? - person dormitkon; 02.03.2011
comment
А у меня в User model method роль? - person dormitkon; 02.03.2011
comment
Это значит, что вы называете роль? метод на нуле. Если вы использовали мой код выше, ваш объект @current_user равен нулю. Вы должны убедиться, что он установлен. Смотрите мое редактирование выше, чтобы узнать, как я это делаю. - person Tony; 02.03.2011

Вам нужно добавить проверки авторизации канкана в ваши контроллеры.

Это может быть просто добавление строки, например

authorize! :read, @state

к вашему действию индекса контроллера состояния, и аналогично для всех других действий индекса.

РЕДАКТИРОВАТЬ: К сожалению, в действии индекса контроллера состояния у вас, вероятно, нет @state, поэтому вышеизложенное неприменимо. Возможно что-то вроде

authorize! :read, State

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

load_and_authorize_resource: состояние

и это должно быть до ваших действий.

Вы можете просмотреть этот авторизацию railscast на канкане для полной базовой настройки ( в рельсах2).

Я подозреваю, что для устранения других проблем нам может понадобиться увидеть еще немного кода. Попробуйте опубликовать код вашего контроллера.

Я не использовал это в rails3, но я предполагаю, что большая часть этого остается более или менее похожей.

person Don Roby    schedule 02.03.2011
comment
И я не могу получить доступ к /state и пользователям, у которых есть разрешения. - person dormitkon; 02.03.2011
comment
Я добавил авторизацию! :index, администратор в контроллере администратора, действие index. Теперь, когда я хочу получить доступ к /admin, зарегистрированному как глобальный пользователь, я получаю NameError в неинициализированной константе AdminController#index AdminController::Admin. Все приложение находится здесь: cl.ly/2E292R2m2B0X141q3C0S - person dormitkon; 02.03.2011
comment
:index, вероятно, все еще должен был быть :read, но я посмотрю на весь ваш контроллер и посмотрю, не увижу ли я что-нибудь. - person Don Roby; 02.03.2011
comment
Админ не существует в вашем коде. Простые примеры для канкана и весь мой код предполагают наличие защищенной модели. Я не очень знаю, как его использовать в отсутствие модели, но, возможно, кто-то еще может помочь. Вам определенно нужно что-то сделать в вашем контроллере, но я не совсем уверен, что в этом контексте. - person Don Roby; 02.03.2011

Я решил эту проблему с

def check_permissions
 raise CanCan::AccessDenied unless current_user.role?(:admin)
end

но обратите внимание, что я должен изменить @current_user на current_user (без @)

Спасибо Тони

person dormitkon    schedule 02.03.2011