【问题标题】:Before filter on condition过滤条件前
【发布时间】:2025-12-31 10:40:07
【问题描述】:

我有一个 Sinatra 应用程序,默认情况下所有路由都需要用户登录。像这样的:

before do 
  env['warden'].authenticate!
end

get :index do
  render :index
end

现在我想使用自定义 Sinatra 条件进行异常处理,但我找不到读取条件是否为真/假/无的方法

def self.public(enable)
  condition {
    if enable 
      puts 'yes'
    else
      puts 'no'
    end
  }
end

before do 
  # unless public?
  env['warden'].authenticate!
end

get :index do
  render :index
end

get :foo, :public => true do
  render :index
end

由于即使未定义条件也必须进行身份验证检查,我想我仍然必须使用before 过滤器,但我不确定如何访问我的自定义条件。

【问题讨论】:

  • 公共方法在之前的上下文中不可用,因为它被定义为类方法。您是否检查过该方法何时被定义为实例方法(没有自我)?
  • 如果我将方法定义为实例(没有 self),那么我将无法将其用作规则条件,并且我想保留在 DSL 中编写公共 url 的这种方式。我在考虑 before 读取请求对象的条件,或者将 public => false 定义为任何规则的默认条件。无论如何,我只是想要一种简单的方法来指定默认规则的一些例外情况。
  • 我注意到的是,条件似乎是在过滤器之后解析的,这就是我没有想法的时候。
  • 到目前为止,我通过仅在检测到登录 url 时有条件地跳过身份验证解决了这个问题,但这不是未来的证明。

标签: filter sinatra


【解决方案1】:

我能够使用 Sinatra 的 helpers 和一些挖掘 Sinatra 的 internals 来解决这个问题。我认为这应该适合你:

helpers do
  def skip_authentication?
    possible_routes = self.class.routes[request.request_method]

    possible_routes.any? do |pattern, _, conditions, _|
      pattern.match(request.path_info) &&
        conditions.any? {|c| c.name == :authentication }
    end
  end
end

before do
  skip_authentication? || env['warden'].authenticate!
end

set(:authentication) do |enabled|
  condition(:authentication) { true } unless enabled
end

get :index do
  render :index
end

get :foo, authentication: false do
  render :index
end

【讨论】: