允许非注册用户使用权威查看内容

时间:2016-11-07 17:31:33

标签: devise ruby-on-rails-4.2 pundit

我在允许未注册/未登录的用户查看索引和显示博客部分的页面时遇到问题。我正在使用Pundit进行授权,并意识到目前我的策略设置为不允许非用户查看博客部分的任何部分,但我不知道如何解决这个问题,因为没有针对索引的策略和显示页面。

我的目标是拥有以下内容:

  

允许管理员和编辑者查看,创建,编辑和删除博客

此部分起作用

  

允许注册用户查看博客

这部分完美无缺

  

允许未注册/未登录的用户查看博客

此部分不起作用

当我尝试将索引页面视为未注册/未登录的用户时,我将获得一个来自我的应用程序控制器的访问被拒绝的闪存消息,该消息正在执行应该执行的操作现行政策。

所以我的问题是:如何修改我的策略以允许未注册/未注册的用户查看索引并仅显示页面?

应用程序控制器

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,但解决方案表明我的情况似乎没有用。

1 个答案:

答案 0 :(得分:0)

经过多次挫折之后,我终于能够解决这个问题了。非常感谢@Scott帮助设置控制器和测试设置,并且几乎使策略有效。

原来raise Pundit::NotAuthorizedError, "must be logged in" unless user的{​​{1}}部分中的initializer不允许未登录的用户访问索引页面(就像你想要的那样)一个封闭的系统......)。由于我的应用程序是开放的,任何人都可以在索引和博客的页面中查看,我需要删除该行。

一旦删除,应用程序就会为尝试访问博客索引页面的未登录用户抛出Application Policy。这是通过使用undefined method admin?' for nil:NilClass中识别用户的正确惯例来解决的。对于策略中的每个def,我都有Post Policy。需要将其更改为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