Ruby Sinatra自定义异常处理内部助手不工作

Ruby Sinatra自定义异常处理内部助手不工作,ruby,exception,jwt,sinatra,Ruby,Exception,Jwt,Sinatra,我正在使用JWT-token创建一个中间件来保护我的sinatra后端应用程序中的特定路由。我将中间件代码移动到助手模块,以便将其添加到需要保护的路由中。问题是当出现异常时。它忽略begin块中的rescue 当JWT.decode引发JWT::ExpiredSignature时,它不在rescue JWT::ExpiredSignature的byebug中,甚至不在救援异常中。它直接转到sinatra/base异常处理,作为错误框架::Lint::LintError:Body生成的非字符串值[

我正在使用
JWT-token
创建一个中间件来保护我的sinatra后端应用程序中的特定路由。我将中间件代码移动到助手模块,以便将其添加到需要保护的路由中。问题是当出现
异常时。它忽略
begin
块中的
rescue

JWT.decode
引发
JWT::ExpiredSignature
时,它不在
rescue JWT::ExpiredSignature
的byebug中,甚至不在
救援异常中。它直接转到sinatra/base异常处理,作为
错误框架::Lint::LintError:Body生成的非字符串值[:status,401]
。是什么导致了这种奇怪的行为

我的代码:

require 'sinatra'
require 'jwt'

helpers do 
    def protected!
        begin
          byebug
          bearer = request.env.fetch('HTTP_AUTHORIZATION').slice(7..-1)
          key = OpenSSL::PKey::RSA.new ENV['PUBLIC_KEY']
          payload = JWT.decode bearer, key, true, { algorithm: 'RS256'}
          claims = payload.first # email, 
          if claims['iss'] == 'user'
            user = User.find_by_email(claims['email'])
            user = User.create({email: claims['email'], role: :user}) if user.nil?
            env[:user] = user
          end
            
        rescue JWT::DecodeError
          halt status: 401, message: 'A token must be passed.'
        rescue JWT::ExpiredSignature 
          byebug # does not get here
          halt status: 403, message: 'The token has expired.'
        rescue JWT::InvalidIssuerError
          halt status: 403, message: 'The token does not have a valid issuer.'
        rescue JWT::InvalidIatError
          halt status: 403, message: 'The token does not have a valid "issued at" time.'
        rescue Pundit::NotAuthorizedError
          halt status: 401, message: 'Unauthorized access.'
        rescue Exception
          byebug # not even here
        end
    end    
end



get '/test' do
    protected!
    
    response = { message: 'Hello world'}
    json response
end
堆栈跟踪:

ERROR Rack::Lint::LintError: Body yielded non-string value [:status, 401]
        /usr/local/var/rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rack-2.2.2/lib/rack/lint.rb:21:in `assert'
        /usr/local/var/rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rack-2.2.2/lib/rack/lint.rb:756:in `block in each'
        /usr/local/var/rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rack-2.2.2/lib/rack/body_proxy.rb:41:in `each'
        /usr/local/var/rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rack-2.2.2/lib/rack/body_proxy.rb:41:in `method_missing'
        /usr/local/var/rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rack-2.2.2/lib/rack/lint.rb:754:in `each'
        /usr/local/var/rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rack-2.2.2/lib/rack/body_proxy.rb:41:in `method_missing'
        /usr/local/var/rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rack-2.2.2/lib/rack/content_length.rb:26:in `call'
        /usr/local/var/rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rack-2.2.2/lib/rack/handler/webrick.rb:95:in `service'
        /usr/local/var/rbenv/versions/2.7.1/lib/ruby/2.7.0/webrick/httpserver.rb:140:in `service'
        /usr/local/var/rbenv/versions/2.7.1/lib/ruby/2.7.0/webrick/httpserver.rb:96:in `run'
        /usr/local/var/rbenv/versions/2.7.1/lib/ruby/2.7.0/webrick/server.rb:307:in `block in start_thread'

我在代码中有两处错误

  • 将错误哈希发送到
    halt
    。这引发了一个例外。正确的形式是
  • halt403,{'Content Type'=>'application/json'},'令牌已过期。

  • 异常顺序由于异常层次结构而混乱:
    JWT::DecodeError
    是比
    JWT::ExpiredSignature
    更高的层次结构。引发的
    JWT::ExpiredSignature
    将被
    JWT::DecodeError
    捕获。最后,我将代码更改为:

    begin
    
    rescue JWT::ExpiredSignature 
      halt 403,{ 'Content-Type' => 'application/json' }, 'The token has expired.'
    rescue JWT::DecodeError
      halt 401,{ 'Content-Type' => 'application/json' }, 'A token must be passed.'
    rescue JWT::InvalidIssuerError
      halt 403,{ 'Content-Type' => 'application/json' }, 'The token does not have a valid issuer.'
    rescue JWT::InvalidIatError
      halt 403,{ 'Content-Type' => 'application/json' }, 'The token does not have a valid "issued at" time.'
    rescue Pundit::NotAuthorizedError
      halt 401,{ 'Content-Type' => 'application/json' }, 'Unauthorized access.'
    
    end
    

  • 我在代码中有两处错误

  • 将错误哈希发送到
    halt
    。这引发了一个例外。正确的形式是
  • halt403,{'Content Type'=>'application/json'},'令牌已过期。

  • 异常顺序由于异常层次结构而混乱:
    JWT::DecodeError
    是比
    JWT::ExpiredSignature
    更高的层次结构。引发的
    JWT::ExpiredSignature
    将被
    JWT::DecodeError
    捕获。最后,我将代码更改为:

    begin
    
    rescue JWT::ExpiredSignature 
      halt 403,{ 'Content-Type' => 'application/json' }, 'The token has expired.'
    rescue JWT::DecodeError
      halt 401,{ 'Content-Type' => 'application/json' }, 'A token must be passed.'
    rescue JWT::InvalidIssuerError
      halt 403,{ 'Content-Type' => 'application/json' }, 'The token does not have a valid issuer.'
    rescue JWT::InvalidIatError
      halt 403,{ 'Content-Type' => 'application/json' }, 'The token does not have a valid "issued at" time.'
    rescue Pundit::NotAuthorizedError
      halt 401,{ 'Content-Type' => 'application/json' }, 'Unauthorized access.'
    
    end
    

  • JWT::ExpiredSignature在哪里定义?您确定它在Sinatra命名空间中可用,并且没有在gem或其他模块中处理吗?此外,请检查Sinatra的raise_errors配置设置的值,该设置仅在默认情况下在测试中启用。您不需要临时变量
    response
    ,只需
    halt status:401,…
    ,然后使用.@ToddA.Jacobs将其交给“jwt”gem处理即可。我忘了在问题代码中添加它。我将编辑
    halt
    不接受这样的散列。您需要执行类似于“必须传递令牌”的操作。
    。这很可能表明您实际上提出了
    JWT::decodererror
    Pundit::NotAuthorizedError
    而不是
    JWT::ExpiredSignature
    ,因为lint错误显示401状态。谢谢@matt。halt参数错误,导致了这种奇怪的行为。我将其固定为“暂停代码,{'Content-Type'=>'application/json'},message”,它开始按预期工作。e、 g.halt 403,{'Content Type'=>'application/json'},'令牌已过期。'JWT::ExpiredSignature在哪里定义?您确定它在Sinatra命名空间中可用,并且没有在gem或其他模块中处理吗?此外,请检查Sinatra的raise_errors配置设置的值,该设置仅在默认情况下在测试中启用。您不需要临时变量
    response
    ,只需
    halt status:401,…
    ,然后使用.@ToddA.Jacobs将其交给“jwt”gem处理即可。我忘了在问题代码中添加它。我将编辑
    halt
    不接受这样的散列。您需要执行类似于“必须传递令牌”的操作。
    。这很可能表明您实际上提出了
    JWT::decodererror
    Pundit::NotAuthorizedError
    而不是
    JWT::ExpiredSignature
    ,因为lint错误显示401状态。谢谢@matt。halt参数错误,导致了这种奇怪的行为。我将其固定为“暂停代码,{'Content-Type'=>'application/json'},message”,它开始按预期工作。e、 g.halt 403,{'Content Type'=>'application/json'},'令牌已过期。'