我在允许未注册/未登录的用户查看索引和显示博客部分的页面时遇到问题。我正在使用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,但解决方案表明我的情况似乎没有用。
答案 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