【问题标题】:Exclude some paths from global authentication in Sinatra从 Sinatra 中的全局身份验证中排除某些路径
【发布时间】:2014-09-07 02:49:32
【问题描述】:

我在 Sinatra 中有一个 API,使用中间件使用令牌进行全局限制身份验证。 该中间件在 before 语句中插入身份验证检查,以便全局保护所有内容,而无需在每个路由定义中添加检查。

before do
  denied unless
    authorized? or
    env['PATH_INFO'] == '/auth/login' or
    env['REQUEST_METHOD'] == 'OPTIONS' # For AngularJS headers checks
end

但现在我有一些路线需要从这个全局限制中排除(只有 2 或 3 条),但不知道该怎么做。

我首先想到的是 Sinatra 条件:http://www.sinatrarb.com/intro.html#Conditions,但由于它在 before 语句中,我无法在之前采取措施避免这种情况。

然后我找到了这个解决方案:Before filter on condition

但这并不是一种真正干净的方法,而且它不适用于中间件和模块化 Sinatra 应用程序。

所以在搜索了很多之后,我需要一些帮助和建议。

如何做到这一点,也许在我的中间件中使用助手、条件和一些修改?

【问题讨论】:

  • 身份验证和授权是两件不同的事情,但从编写方式来看,它们似乎是混为一谈的。只是说。
  • @iain 不是。所有的 API 都需要身份验证,所以要么您已经获得授权,要么您需要进行身份验证,这就是这样做的目的。
  • 好的,谢谢你清理它:)

标签: ruby authentication sinatra


【解决方案1】:

为什么不把不需要授权的路由列表放到一个数组中查看呢?

configure do
  set :no_auth_neededs, ['/auth/login', "/a", "/b", "/c"]
end

before do
  denied unless
    authorized? or
    settings.no_auth_neededs.include?(env['PATH_INFO']) or
    env['REQUEST_METHOD'] == 'OPTIONS' # For AngularJS headers checks
end

我还没有测试过。


更新:

如果我投入 10 秒的思考时间,我还可以想到其他两种方法,我的懒惰不会抱怨……但我很乐意相信直觉 :)

扩展 DSL

写一个authorised_route处理程序:

require 'sinatra/base'

module Sinatra
  module AuthorisedRoute
    def authorised_route(verb,path,&block)
      before path do
        denied unless
          authorized? or
          request.request_method == 'OPTIONS' # For AngularJS headers checks
      end
      send verb.to_sym, path, &block
    end
  end

  register AuthorisedRoute
end

class API < Sinatra::Base
  register AuthorisedRoute

  authorised_route "get", "/blah" do
    # blah
  end

  get "/free-route" do
    # blah
  end
end

您可以删除 before 块并将逻辑放入路径中,YMMV。有很多方法可以使用这种东西。注意将env 替换为request(参见Accessing the Request Object

See the docs for more on DSL extensions

使用类

分离出两种类型的路线,这就是类的用途,共享属性和/或行为的事物组:

require 'sinatra/base'

class AuthedAPI < Sinatra::Base

  before do
    denied unless
      authorized? or
      request.request_method == 'OPTIONS' # For AngularJS headers checks
  end

  # you should probably add the `denied` and `authorized?` helpers too

  # list of routes follow…
end

# define route that don't need auth in here
class OpenAPI < Sinatra::Base
  get "/auth/login" do
    # stuff…
  end
end

class API < Sinatra::Base
  use OpenAPI  # put OpenAPI first or a `denied` will happen.
  use AuthedAPI
end

然后在 rackup 文件中将 API 映射到 "/"(或任何 API 的根路径)。只有 AuthedAPI 中的路由会受到 before 块的约束。

【讨论】:

  • 这是个好主意,如果我找不到其他任何东西,我现在肯定会走这条路。但我更喜欢在定义路由时这样做,如果有任何合适的方式来做的话,因为我需要过滤路由和访问它的具体方法。
  • @Sylver 我已经用一些您可能感兴趣的替代方案更新了答案。
  • 我认为我会选择 DSL 扩展,感谢您对此的所有聪明想法!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-10
  • 2023-04-08
  • 2013-01-06
  • 2022-12-16
  • 2016-11-13
  • 1970-01-01
相关资源
最近更新 更多