允许非注册用户使用专家查看内容
Allow non registered users to view content with pundit
我无法让 non-registered/non-logged 用户查看索引并显示博客部分的页面。我正在使用 Pundit 进行授权,并意识到目前我的政策设置为不允许非用户查看博客部分的任何部分,但我不知道如何解决这个问题,因为没有索引政策和显示页面。
我的目标是:
Allow Admin and Editors to view, create, edit, and delete blogs
这部分工作完美
Allow registered users to view blogs
这部分完美
Allow non-registered/non-logged in users to view blogs
这部分不行
当我尝试以用户 non-registered/non-logged 的身份查看索引页面时,我会收到一条来自我的应用程序控制器的访问被拒绝的闪现消息,它正在做它应该做的事情当前政策。
所以我的问题是:如何修改我的策略以允许 non-registered/non-logged 用户仅查看索引和显示页面?
应用程序控制器
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
Post 政策
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
Post 控制器
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
我看到有人问过类似的问题 ,但那里建议的解决方案似乎对我的情况不起作用。
几经折腾,终于解决了这个问题。非常感谢@Scott 帮助我们按照应有的方式设置控制器和测试,并且几乎让策略生效。
原来 Application Policy
的 initializer
部分中的 raise Pundit::NotAuthorizedError, "must be logged in" unless user
不允许未登录的用户访问索引页面(就像它应该在你想要一个封闭的系统......)。由于我的应用程序是开放的,任何人都可以在索引中查看并显示博客页面,因此我需要删除该行。
删除后,应用程序会为尝试访问博客索引页面的未登录用户抛出 undefined method admin?' for nil:NilClass
。这是通过使用 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
Post 政策
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 控制器
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
我无法让 non-registered/non-logged 用户查看索引并显示博客部分的页面。我正在使用 Pundit 进行授权,并意识到目前我的政策设置为不允许非用户查看博客部分的任何部分,但我不知道如何解决这个问题,因为没有索引政策和显示页面。
我的目标是:
Allow Admin and Editors to view, create, edit, and delete blogs
这部分工作完美
Allow registered users to view blogs
这部分完美
Allow non-registered/non-logged in users to view blogs
这部分不行
当我尝试以用户 non-registered/non-logged 的身份查看索引页面时,我会收到一条来自我的应用程序控制器的访问被拒绝的闪现消息,它正在做它应该做的事情当前政策。
所以我的问题是:如何修改我的策略以允许 non-registered/non-logged 用户仅查看索引和显示页面?
应用程序控制器
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
Post 政策
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
Post 控制器
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
我看到有人问过类似的问题
几经折腾,终于解决了这个问题。非常感谢@Scott 帮助我们按照应有的方式设置控制器和测试,并且几乎让策略生效。
原来 Application Policy
的 initializer
部分中的 raise Pundit::NotAuthorizedError, "must be logged in" unless user
不允许未登录的用户访问索引页面(就像它应该在你想要一个封闭的系统......)。由于我的应用程序是开放的,任何人都可以在索引中查看并显示博客页面,因此我需要删除该行。
删除后,应用程序会为尝试访问博客索引页面的未登录用户抛出 undefined method admin?' for nil:NilClass
。这是通过使用 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
Post 政策
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 控制器
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