Rails是否带有“未授权”的例外?
我正在编写一个使用普通旧Ruby对象(PORO)从控制器中抽象出授权逻辑的应用程序。
目前,我有一个名为NotAuthorized
的自定义exception类,我在控制器级别NotAuthorized
,但我很想知道: Rails 4是否已经出现exception以表明某个操作未被授权? 我是否通过实施此例外来重新发明轮子?
澄清 : raise AuthorizationException
不会发生在控制器内部的任何地方,它发生在控制器外部完全解耦的PORO内部。 该对象不了解HTTP,路由或控制器。
Rails似乎没有将exception映射到:unauthorized
。
默认映射在activerecord / lib / active_record / railtie.rb中定义 :
config.action_dispatch.rescue_responses.merge!( 'ActiveRecord::RecordNotFound' => :not_found, 'ActiveRecord::StaleObjectError' => :conflict, 'ActiveRecord::RecordInvalid' => :unprocessable_entity, 'ActiveRecord::RecordNotSaved' => :unprocessable_entity )
和actionpack / lib / action_dispatch / middleware / exception_wrapper.rb :
@@rescue_responses.merge!( 'ActionController::RoutingError' => :not_found, 'AbstractController::ActionNotFound' => :not_found, 'ActionController::MethodNotAllowed' => :method_not_allowed, 'ActionController::UnknownHttpMethod' => :method_not_allowed, 'ActionController::NotImplemented' => :not_implemented, 'ActionController::UnknownFormat' => :not_acceptable, 'ActionController::InvalidAuthenticityToken' => :unprocessable_entity, 'ActionDispatch::ParamsParser::ParseError' => :bad_request, 'ActionController::BadRequest' => :bad_request, 'ActionController::ParameterMissing' => :bad_request )
您可以在应用程序的配置(或自定义Railtie )中添加自定义exception:
Your::Application.configure do config.action_dispatch.rescue_responses.merge!( 'AuthorizationException' => :unauthorized ) # ... end
或者只是使用rescue_from
。
我猜测Rails没有引入此exception的原因是因为授权和身份validation不是Rails本机行为(当然不考虑basicauth)。
通常这些是其他图书馆的责任设计 Not Notheutheated; Pundit ,CanCanCan,Rollify for NotAuthorized)我实际上认为用ActionController::NotAuthorized
等自定义exception来扩展ActionController
可能是件ActionController::NotAuthorized
(因为就像我说它不是它的责任)
所以我通常解决这个问题的方法是我在ApplicationController
上引入了自定义exception
class ApplicationController < ActionController::Base NotAuthorized = Class.new(StandardError) # ...or if you really want it to be ActionController # NotAuthorized = Class.new(ActionController::RoutingError) rescue_from ActiveRecord::RecordNotFound do |exception| render_error_page(status: 404, text: 'Not found') end rescue_from ApplicationController::NotAuthorized do |exception| render_error_page(status: 403, text: 'Forbidden') end private def render_error_page(status:, text:, template: 'errors/routing') respond_to do |format| format.json { render json: {errors: [message: "#{status} #{text}"]}, status: status } format.html { render template: template, status: status, layout: false } format.any { head status } end end end
因此在我的控制器中我能做到
class MyStuff < ApplicationController def index if current_user.admin? # .... else raise ApplicationController::NotAuthorized end end end
这清楚地定义了您期望引发此exception的层是您的应用程序层,而不是第三方库。
问题是库可以改变(是的,这也就是Rails)在第三方库类上定义exception并在应用程序层中拯救它们是非常危险的,好像exception类的含义改变它会使你的rescue_from
你可以阅读很多文章,其中人们正在关注Rails raise
- rescue_from
是现代goto
(现在考虑一些专家的反模式)并且在某种程度上它是真的,但只有当你正在拯救你没有的例外情况时完全控制!!
这意味着第三方例外(包括Devise和Rails到某一点)。 如果你在应用程序中定义了exception类,你就不会在第三方lib =>你完全控制=>你可以rescue_from
而不是反模式。