2016-11-07 1 views
0

У меня возникли проблемы с тем, чтобы незарегистрированные/не зарегистрированные пользователи просматривали индекс и показывали страницы для раздела блога. Я использую Pundit для авторизации и понимаю, что на данный момент у меня есть политики, запрещающие не пользователям просматривать какую-либо часть раздела блога, но я понятия не имею, как обойти это, чтобы не иметь политики для индекса и показать страницу.Разрешить незарегистрированным пользователям просматривать содержимое с помощью pundit

Моя цель состоит в том, чтобы иметь следующее:

Разрешить администратора и редакторы для просмотра, создания, редактирования и удаления блоги

Эта часть работает Pefect

Allow зарегистрировано пользователи для просмотра блогов

Эта часть работает отлично

Разрешить незарегистрированные/не зарегистрированных пользователей, чтобы просмотреть блоги

Эта часть не работает

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

Итак, мой вопрос: как мне изменить свои правила, чтобы пользователи, не зарегистрированные или не зарегистрированные, просматривали только индекс и показывали страницы?

Контроллер Применение

class ApplicationController < ActionController::Base 
    include Pundit 
    rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized 

    # Prevent CSRF attacks by raising an exception. 
    # For APIs, you may want to use :null_session instead. 
    protect_from_forgery with: :exception 
    before_filter :configure_permitted_parameters, if: :devise_controller? 

    private 

    def user_not_authorized(exception) 
     flash[:danger] = "Access denied. You are not authorized to view that page." 
     redirect_to (request.referrer || root_path) 
    end 


protected 

    def configure_permitted_parameters 
    devise_parameter_sanitizer.permit(:sign_up) { |u| u.permit(:username, :email, :password, :password_confirmation, :remember_me) } 
    devise_parameter_sanitizer.permit(:sign_in) { |u| u.permit(:username, :email, :password, :remember_me) } 
    devise_parameter_sanitizer.permit(:account_update) {|u| u.permit(:username, :email, :password, :password_confirmation, :current_password)} 
    end 


end 

Политика Применение

class ApplicationPolicy 
    attr_reader :user, :record 

    def initialize(user, record) 
    raise Pundit::NotAuthorizedError, "You must be logged in to perform this action" unless user 
    @user = user 
    @record = record 
    end 

    def index? 
    true 
    end 

    def show? 
    scope.where(:id => record.id).exists? 
    end 

    def create? 
    false 
    end 

    def new? 
    create? 
    end 

    def update? 
    false 
    end 

    def edit? 
    update? 
    end 

    def destroy? 
    false 
    end 

    def scope 
    Pundit.policy_scope!(user, record.class) 
    end 

    class Scope 
    attr_reader :user, :scope 

    def initialize(user, scope) 
     @user = user 
     @scope = scope 
    end 

    def resolve 
     scope 
    end 
    end 
end 

Сообщение Политика

class PostPolicy < ApplicationPolicy 
    attr_reader :post 

    class Scope < Scope 
    def resolve 
     if user&.admin?&.editor?&.user? 
     scope.all 
     else user != admin? || editor? || user? 
     scope 
     end 
    end 
    end 

    def permitted_attributes 
    if user.admin? || user.editor? 
     [:title, :body, :image, :permalink, :description, :tag_list, :username] 
    else 
     [:title, :body, :image, :username] 
    end 
    end 

    def index? 
    true 
    end 

    def show? 
    true 
    end 

    def new? 
    user.admin? || user.editor? 
    end 

    def create? 
    user.admin? || user.editor? 
    end 

    def update? 
    user.admin? || user.editor? 
    end 

    def destroy? 
    user.admin? || user.editor? 
    end 
end 

Сообщение Контроллер

class PostsController < ApplicationController 
    before_action :set_post, only: [:show, :edit, :update, :destroy] 
    after_action :verify_authorized, only: [:destroy] 

    def index 
    @meta_title = "Blog" 
    @meta_description = "page description here" 
    @posts = Post.all.order("created_at DESC").paginate(:page => params[:page], :per_page => 4) 
    end 

    def show 
    @meta_title = @post.title 
    @meta_description = @post.description 
    end 

    def new 
    @meta_title = "Add New Blog" 
    @meta_description ="Add a new blog." 
    @post = Post.new 
    authorize @post 
    end 

    def edit 
    @meta_title = "Edit Blog" 
    @meta_description ="Edit an existing blog." 
    authorize @post 
    end 

    def create 
    @post = Post.new 
    @post.update_attributes(permitted_attributes(@post)) 
    @post.user = current_user if user_signed_in? 

    authorize @post 

    if @post.save 
     redirect_to @post, notice: 'Post was successfully created.' 
    else 
     render :new 
    end 
    end 

    def update 
    @post = Post.find(params[:id]) 
    if @post.update_attributes(permitted_attributes(@post)) 
     authorize @post 
     redirect_to @post, notice: 'Post was successfully updated.' 
    else 
     render :edit 
    end 
    end 

    def destroy 
    if @post.present? 
     @post.destroy 
     authorize @post 
    else 
     skip_authorization 
    end 

    redirect_to posts_url, notice: 'Post was successfully deleted.' 
    end 

    private 
    # Use callbacks to share common setup or constraints between actions. 
    def set_post 
     @post = Post.find(params[:id]) 
    end 

    # Only allow the white list through. 
    def post_params 
     params.require(:post).permit(policy(@post).permitted_attributes) 
    end 
end 

Я видел подобный вопрос спросил Pundit policy_scoper error, но решение, предложенное не кажется, что работать в моем случае.

+0

Похоже, что он даже не должен ударять по вашей политике из указателя или действия шоу, так как вы не вызываете 'authorize' в любом действии. Что произойдет, если вы добавите 'authorize Post' в действие вашего индекса? Я бы подумал, так как вы возвращаетесь в PostPolicy.index? что он должен работать. – Scott

+0

Привет @scott Я попробовал как , так и . не имел эффекта и <@post> создал ошибку . <@post> работает для всех других действий в индексе, как вы можете видеть в контроллере. – Nate

+0

@Scott есть ли у вас какие-либо другие идеи или идеи? Я все еще изо всех сил пытаюсь преодолеть эту проблему. Я попробовал все: добавив в индекс skip_authorization в индекс, чтобы удалить индекс и показать def из политики для сообщений, а затем как должности, так и политики приложений. Независимо от того, что я до сих пор получаю флеш-сообщение «Не авторизован» при попытке доступа в качестве пользователя без входа/гостя. – Nate

ответ

0

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

Оказывается, что raise Pundit::NotAuthorizedError, "must be logged in" unless user в initializer части Application Policy не позволяет без зарегистрированных пользователей доступа к индексной странице (так же, как это предполагается, когда вы хотите закрытую систему ...). Поскольку мое приложение открыто для тех, кто просматривает страницы индексирования и показа блога, мне нужно было удалить эту строку.

После удаления приложение затем выкинет undefined method admin?' for nil:NilClass для незарегистрированных пользователей, пытающихся получить доступ к странице индекса блога. Это было решено с помощью правильных соглашений об идентификации пользователей в Post Policy. Для каждого def в политике у меня было user.admin? || user.editor?. Это необходимо было изменить на user&.admin? || user&.editor?.

Код закончилась следующим образом:

политики Application

class ApplicationPolicy 
    attr_reader :user, :record 

    def initialize(user, record) 
    @user = user 
    @record = record 
    end 

    def index? 
    false 
    end 

    def show? 
    scope.where(:id => record.id).exists? 
    end 

    def create? 
    false 
    end 

    def new? 
    create? 
    end 

    def update? 
    false 
    end 

    def edit? 
    update? 
    end 

    def destroy? 
    false 
    end 

    def scope 
    Pundit.policy_scope!(user, record.class) 
    end 

    class Scope 
    attr_reader :user, :scope 

    def initialize(user, scope) 
     @user = user 
     @scope = scope 
    end 

    def resolve 
     scope 
    end 
    end 
end 

Сообщение политики

class PostPolicy < ApplicationPolicy 

    attr_reader :post 


    class Scope < Scope 
    def resolve 
     if user&.admin? || user&.editor? 
     scope.all 
     else 
     end 
    end 
    end 

    def permitted_attributes 
    if user.admin? || user.editor? 
     [:title, :body, :image, :permalink, :description, :tag_list, :username] 
    else 
     [:title, :body, :image, :username] 
    end 
    end 

    def index? 
    true 
    end 

    def show? 
    true 
    end 

    def new? 
    admin_or_editor 
    end 

    def create? 
    admin_or_editor 
    end 

    def update? 
    admin_or_editor 
    end 

    def destroy? 
    admin_or_editor 
    end 

    private 

    def admin_or_editor 
    user&.admin? || user&.editor? 
    end 
end 

Post Controller

class PostsController < ApplicationController 
    before_action :set_post, only: [:show, :edit, :update, :destroy] 
    before_action :authenticate_user!, except: [:index, :show] 
    after_action :verify_authorized, except: [:index, :show] 

    def index 
    @meta_title = "Blog" 
    @meta_description = "blog description" 
    @posts = Post.all.order("created_at DESC").paginate(:page => params[:page], :per_page => 4) 
    end 

    def show 
    @meta_title = @post.title 
    @meta_description = @post.description 
    end 

    def new 
    @meta_title = "Add New Blog" 
    @meta_description ="Add a new blog." 
    @post = Post.new 
    authorize @post 
    end 

    def edit 
    @meta_title = "Edit Blog" 
    @meta_description ="Edit an existing blog." 
    authorize @post 
    end 

    def create 
    @post = Post.new 
    @post.update_attributes(permitted_attributes(@post)) 
    @post.user = current_user if user_signed_in? 

    authorize @post 

    if @post.save 
     redirect_to @post, notice: 'Post was successfully created.' 
    else 
     render :new 
    end 
    end 

    def update 
    @post = Post.find(params[:id]) 
    authorize @post 
    if @post.update_attributes(permitted_attributes(@post)) 
     redirect_to @post, notice: 'Post was successfully updated.' 
    else 
     render :edit 
    end 
    end 

    def destroy 
    if @post.present? 
     @post.destroy 
     authorize @post 
    else 
     skip_authorization 
    end 

    redirect_to posts_url, notice: 'Post was successfully deleted.' 
    end 

    private 
    # Use callbacks to share common setup or constraints between actions. 
    def set_post 
    @post = Post.find(params[:id]) 
    end 

    # Only allow the white list through. 
    def post_params 
    params.require(:post).permit(policy(@post).permitted_attributes) 
    end 
end