ruby-on-rails - Pundit:如何为一项未经授权的操作处理多个错误代码?
问题描述
我使用 pundit 来处理我的 API 策略,我有一个项目显示,在某些情况下可以禁止用户使用,而在其他情况下只是受限。受限我的意思是它现在被禁止了,但如果他付钱,他就可以访问它。因此,我需要我的 API 以特定代码 ( 402 Payment Required
) 进行响应,以便客户端可以邀请用户付款以解锁节目。
这是我当前的代码,它仅403
在权威返回 false 时响应。
为了干燥和清洁,最好在哪里实施返回403
OR的条件?402
class Api::V1::ItemController < Api::V1::BaseController
def show
@item = Item.find(params[:id])
authorize @item
end
end
class ItemPolicy < ApplicationPolicy
def show?
return true if record.public?
# 403 will be generated, that's ok.
return false if !record.band.members.include?(user)
# If that condition is false I want to generate a 402 error at the end, not a 403.
user.premium?
end
end
class Api::V1::BaseController < ActionController::API
include Pundit
rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized
def user_not_authorized(_exception)
# Here I've got the exception with :policy, :record and :query,
# also I can access :current_user so I could go for a condition,
# but that would include duplicated code from ItemPolicy#show?.
render json: { error: { message: "Access denied" } }, status: :forbidden
end
end
解决方案
不幸Pundit
的是,无法开箱即用地处理不同的错误类型。它的构建始终期望策略的方法返回true
或 false false
。因此,在控制器中引发另一个自定义错误并从中解救是行不通的,因为它也会破坏视图方法。
我建议一种解决方法来引入不同的错误类型。像这样的东西可能会起作用:
# in the policy
class ItemPolicy < ApplicationPolicy
def show?
return true if record.public?
return false unless record.band.members.include?(user)
if user.premium?
true
else
Current.specific_response_error_code = :payment_required
false
end
end
end
# in the controller
class Api::V1::BaseController < ActionController::API
include Pundit
rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized
def user_not_authorized(_exception)
case Current.specific_response_error_code
when :payment_required
render json: { error: { message: "Premium required" } }, status: :payment_required
else
render json: { error: { message: "Access denied" } }, status: :forbidden
end
end
end
我不认为使用全局CurrentAttributes
是一个好的做法,但它们是 Rails 的一部分,在这种情况下,使用这个全局数据存储可以避免覆盖权威内部。
您可能想阅读有关CurrentAttributes
.
推荐阅读
- django - 浏览器阻止跨域 iframe cookie
- python - Unable to utilize sys args to modify variables
- networking - Disease network
- html - Calculate Content-Length in HTTP Header
- reactjs - Gatsby and GraphQL: Accessing data in a template page
- python - 文件中提取号码的问题
- html - Is there a way I can have 2 div elements on top of each other but not overlapping?
- android - 安卓数据绑定。按钮 onClick 不起作用
- sql - 如何从 SQL 中另一个表的列生成随机值?
- opencv - 安装 pip 时在 C++ 中包含 OpenCV