Ruby-on-rails Rails 是否带有“未授权”例外?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25892194/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 23:55:38  来源:igfitidea点击:

Does Rails come with a "not authorized" exception?

ruby-on-railsrubyactioncontroller

提问by Rick

I am writing an application that uses plain old Ruby objects (POROs) to abstract authorization logic out of controllers.

我正在编写一个应用程序,它使用普通的旧 Ruby 对象 (PORO) 从控制器中抽象出授权逻辑。

Currently, I have a custom exception class called NotAuthorizedthat I rescue_fromat the controller level, but I was curious to know: Does Rails 4 already come with an exception to indicate that an action was not authorized?Am I reinventing the wheel by implementing this exception?

目前,我有调用自定义异常类NotAuthorized,我rescue_from在控制器级别,但我很好奇,想知道:不导轨4已经配备了一个例外,表明一个动作没有被授权?我是否通过实施此异常来重新发明轮子?

Clarification: The raise AuthorizationExceptionis not happening anywhere inside of a controller, it is happening inside of a completely decoupled PORO outside of the controller. The object has no knowledge of HTTP, routes or controllers.

澄清:这raise AuthorizationException不会发生在控制器内部的任何地方,而是发生在控制器外部完全解耦的 PORO 内部。该对象不知道 HTTP、路由或控制器。

采纳答案by Stefan

Rails doesn't seem to map an exception to :unauthorized.

Rails 似乎没有将异常映射到:unauthorized.

The default mappings are defined in activerecord/lib/active_record/railtie.rb:

默认映射在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
)

and actionpack/lib/action_dispatch/middleware/exception_wrapper.rb:

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
)

You could add a custom exception from within your application's configuration (or a custom Railtie):

您可以从应用程序的配置(或自定义Railtie)中添加自定义异常:

Your::Application.configure do

  config.action_dispatch.rescue_responses.merge!(
    'AuthorizationException' => :unauthorized
  )

  # ...

end

Or simply use rescue_from.

或者干脆使用rescue_from.

回答by equivalent8

I'm guessing the reason Rails didn't introduce this exception is because Authorisation and Authentication is not Rails native behavior (not considering basicauth of course).

我猜 Rails 没有引入这个异常的原因是因为授权和身份验证不是 Rails 的本机行为(当然不考虑 basicauth)。

Usually these are responsibilities of other libraries Devisefor NotAuthenticated; Pundit, CanCanCan, Rollify for NotAuthorized) I would actually argue it may be a bad thing to extend ActionControllerwith custom exceptions like ActionController::NotAuthorized(because like I said it's not it's responsibility)

通常这些是其他库为 NotAuthenticated设计的职责;Pundit, CanCanCan, Rollify for NotAuthorized) 我实际上认为ActionController使用自定义异常进行扩展可能是一件坏事,例如ActionController::NotAuthorized(因为就像我说的这不是责任)

So Way how I usually tackled this problem is that I've introduced custom exceptions on ApplicationController

所以我通常解决这个问题的方式是我在 ApplicationController

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

Therefore in my controllers I can do

因此在我的控制器中我可以做到

class MyStuff < ApplicationController
  def index
    if current_user.admin?
      # ....
    else 
      raise ApplicationController::NotAuthorized
    end
  end
end

This clearly defines that the layer your expecting this exception to be raised and caught is your application layer, not 3rd party lib.

这清楚地定义了您期望引发和捕获此异常的层是您的应用程序层,而不是第 3 方库。

The thing is that libraries can change (and yes this means Rails too) defining exception on a 3rd party lib classes and rescuing them in your application layer is really dangerous as if the meaning of exception class changes it brakes your rescue_from

问题是库可以更改(是的,这也意味着 Rails)在第 3 方 lib 类上定义异常并在您的应用程序层中拯救它们真的很危险,好像异常类的含义改变了它会阻止您 rescue_from

You can read lot of articles where people are Waring about Rails raise- rescue_frombeing the modern goto(now considering anti-pattern amongst some experts) and in certain extend it is true, but only if you are rescuing Exceptions that you don't have full control off !!

你可以阅读很多关于 Rails 的文章raise——rescue_from它是现代的goto(现在正在考虑一些专家的反模式)并且在某种程度上这是真的,但前提是你正在拯救你无法完全控制的异常!!

That means 3rd party exceptions (including Devise and Rails to certain point). If you define the exceptions classes in your application, you are not relaying on 3rd party lib => you have full control => you can rescue_fromwithout this being an anti-pattern.

这意味着 3rd 方例外(包括 Devise 和 Rails 到某个点)。如果您在应用程序中定义了异常类,则您不会在第 3 方库上进行中继 => 您拥有完全控制权 => 您可以rescue_from不使用这种反模式。