Ученый: авторизовать определенный ресурс для контроллера с другим именем

Допустим, я использую гем Pundit для авторизации. У меня есть следующий контроллер:

class BlogsController < ApplicationController
  before_action :check_authorization
  ...

  private
  def check_authorization
    authorize :blog
  end
end

Pundit смотрит на переданный аргумент :blog и, таким образом, делает вывод, что существует класс BlogPolicy. Затем он ищет соответствующее имя действия со знаком вопроса, например: BlogPolicy#index?.

Если я хочу найти авторизацию на определенном ресурсе, я бы просто сделал это для этого метода check_authorization:

  def check_authorization
    authorize @blog
  end

Опять же, нет проблем. Pundit смотрит на класс ресурса Blog, а затем ищет класс BlogPolicy.

  • Пример. Приложение может вызвать метод BlogPolicy#show? и передать этот ресурс @blog.

Вот проблема: что мне делать, когда я хочу авторизоваться на определенном имени контроллера И авторизоваться на определенном ресурсе, но этот ресурс не синхронизируется с именем контроллера?

Пример:

class SomeOtherBlogsController < ApplicationController
  before_action :check_authorization
  ...

  private
  def check_authorization
    authorize :some_other_blog, @blog
  end
end

Приведенный выше код не работает, но, надеюсь, он показывает, что я пытаюсь сделать. Давайте представим, что это происходит в действии SomeOtherBlogsController#show.

  • Я пытаюсь, чтобы эксперт нашел метод SomeOtherBlogPolicy#show?,
  • В рамках этого метода политики я также хочу проверить авторизационный доступ к ресурсу @blog.

Надеюсь, проблема очевидна. Поскольку класс ресурсов не синхронизируется с именем контроллера, похоже, я не могу сделать это выше. Так что, если у меня есть один и тот же ресурс, используемый в разных контроллерах, мне не повезло. Я бы не смог проверить авторизацию ресурса в этих различных контекстах контроллера. Это невозможно сделать с Пандитом?

Обновление:

В контроллере я также попытался напрямую вызвать метод Policy следующим образом:

SomeOtherBlogPolicy.new(current_user, @blog).show?

Однако колл поднял Pundit::AuthorizationNotPerformedError. Таким образом, оказывается, что в этом методе authorize происходит больше, чем просто возврат true или false.


person Neil    schedule 23.03.2018    source источник


Ответы (3)


Вы можете вручную указать класс ресурсов для модели:

class Blog
  def self.policy_class
    SomeOtherBlogPolicy
  end
end

К сожалению, невозможно указать класс политики из контроллера при вызове authorize...

Это было правдой, когда я изначально написал ответ. v2.00 добавлена ​​опция policy_class для авторизации:

authorize(@blog, policy_class: SomeOtherBlogPolicy)

Таким образом, обходной путь в моем первоначальном ответе больше не нужен.

person max    schedule 23.03.2018
comment
поскольку github.com/varvet/pundit/commit/ возможно - person Keeper Hood; 26.11.2019

Теперь это встроенная функция в версии Pundit 2.0.0.. В документацию добавлено следующее:

При необходимости вы можете передать аргумент, чтобы переопределить класс политики. Например:

def create
  @publication = find_publication # assume this method returns any model that behaves like a publication
  # @publication.class => Post
  authorize @publication, policy_class: PublicationPolicy
  @publication.publish!
  redirect_to @publication
end
person Neil    schedule 20.09.2018

Можно ли также переопределить класс политики в представлении? Я пытался это сделать, но получил ошибку unknown keyword: :policy_class

<% if policy(@publication, policy_class: PublicationPolicy).create? %>
person vince    schedule 04.08.2020
comment
Я не уверен, решит ли это ваш вариант использования, но я сделал следующее: <% if policy(:publication).my_custom_policy_in_application_policy? %>. По сути: я помещаю настроенные политики в ApplicationPolicy, и они доступны из всех моих других политик, потому что все они наследуются от ApplicationPolicy. Проблема, конечно, в том, что если ваша авторизация основана на фактической записи @publication, то это не сработает для вас. - person Neil; 07.08.2020