2016-11-07 64 views
0

我無法允許未註冊/未登錄的用戶查看索引並顯示博客部分的頁面。我正在使用Pundit進行授權,並意識到目前我的政策設置爲不允許非用戶查看博客部分的任何部分,但我不知道如何解決該問題,以便對索引沒有政策並且顯示頁面。允許非註冊用戶查看具有評論者的內容

我的目標是具備以下條件:

允許管理員和編輯器來查看,創建,編輯和刪除博客

這部分工作pefect

允許註冊用戶查看博客

這部分工作完美

允許非註冊/非登錄用戶查看博客

這部分不工作

當我嘗試查看索引頁面一個未註冊/未登錄的用戶,我將得到一個訪問被拒絕的閃存消息,它出自我的應用程序控制器,它正在執行當前策略下應該執行的操作。

所以我的問題是:如何修改我的策略以允許非註冊/未登錄的用戶只查看索引和顯示頁面?

應用控制器

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

它看起來應該不會從索引觸發您的策略或顯示操作,因爲您在任一操作中都沒有調用「授權」。如果您將「授權Post」添加到您的索引操作會發生什麼?我會想,因爲你在PostPolicy.index中返回true?它應該工作。 – Scott

+0

Hi @scott我試了已無效,<@post>創建了錯誤。您可以在控制器中看到<@post>適用於索引中的所有其他操作。 – Nate

+0

@Scott你有任何其他想法或見解?我仍然努力克服這個問題。我已經嘗試了一切,從索引中的skip_authorization添加到刪除索引,並顯示def超出了發佈的策略,然後是帖子和應用程序策略。無論如何,當以未登錄/訪客用戶的身份訪問時,仍然會收到「未經授權」的閃存消息。 – Nate

回答

0

經過多次挫折,我終於能夠解決這個問題。非常感謝@Scott幫助獲得控制器和測試設置,並且幾乎可以實現策略的正常工作。

原來,在Application Policyinitializer部分raise Pundit::NotAuthorizedError, "must be logged in" unless user沒有允許非登錄訪問索引頁(就像它應該當你想要一個封閉的系統......)的用戶。由於我的應用程序對任何人都可以在博客的索引和顯示頁面中查看,所以我需要刪除該行。

一旦被移除,應用程序將爲嘗試訪問博客索引頁面的未登錄用戶投擲undefined method admin?' for nil:NilClass。這是通過在Post Policy中使用正確的識別用戶的慣例來解決的。對於政策中的每個def,我都有user.admin? || user.editor?。這需要更改爲user&.admin? || user&.editor?

代碼結束如下:

應用策略

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 

柱控制器

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