机架中间件无法在Sinatra中重定向身份验证

时间:2015-03-20 09:49:07

标签: authentication sinatra rack middleware

为什么在与Sinatra应用程序中的默认GET和POST登录路由以及401处理相结合时,Rack中间件无法重定向?

相关的Shield中间件提取:

module Shield
  class Middleware
    attr :url

    def initialize(app, url = "/login")
      @app = app
      @url = url
    end

    def call(env)
      tuple = @app.call(env)

      if tuple[0] == 401
        [302, headers(env["SCRIPT_NAME"] + env["PATH_INFO"]), []]
      else
        tuple
      end
    end

  private
    def headers(path)
      { "Location" => "%s?return=%s" % [url, encode(path)],
        "Content-Type" => "text/html",
        "Content-Length" => "0"
      }
    end

    def encode(str)
      URI.encode_www_form_component(str)
    end
  end
end

查看full source code(104行/2.8kb)。

这是Sinatra应用程序的相关摘录:

# application_controller.rb
class ApplicationController < Sinatra::Base
  helpers Shield::Helpers
  use Shield::Middleware, "/login"
  ...

  get '/noway' do
    error(401) unless authenticated(User)
    erb :app_noway
  end  

  get '/login' do
    erb :login
  end

  post "/login" do
    if login(User, params[:login], params[:password])
      remember(authenticated(User)) if params[:remember_me]
      redirect(params[:return] || "/")          
    else
      redirect "/login"
    end
  end
end

完整源代码(显示问题行为的基本应用),方便快捷查看:https://github.com/shieldtest/shieldtest

存储库已准备好进行克隆和机架式处理。与数据库,环境和所有。登录信息;电子邮件:shield@example.org,密码:shield。

问题
当访问受保护的路由(/ noway)时,中间件会按预期注入身份验证过程。但在成功进行身份验证后,后续重定向始终默认为root,而不是受保护页面的返回URL(/ noway)。

需要解决方案
通过Shield成功验证后,受保护的页面(/ noway)应自动重定向到。

<小时/> 直观漫游

第1步(下方):在Sinatra主页上。点击链接到受保护页面(/ noway) enter image description here

步骤2(如下):正确地重定向到/ login,因为没有用户通过身份验证。正确输入正确的登录凭据 enter image description here

问题行为 - 重定向到主页而不是受保护的页面步骤3A(下方):输入正确的登录凭据后:再次发送回主页(再次)
enter image description here

测试登录 - 现在可以访问受保护的页面(手动,再次点击页面)
步骤4(下面):在主页面上。再次点击受保护的页面(/ noway)=&gt;授予访问权限 enter image description here

1 个答案:

答案 0 :(得分:0)

似乎params[:return]从未转发到POST请求。

因此,'脏修复'将获取返回参数并通过登录表单将其传递给POST请求。这会产生所需的行为:

#login.rb
...
<% if params[:return] %>
  <input type='hidden' name='redirect' value="<%= params[:return] %>">
<% end %>
...

然后从登录表单重定向到重定向参数:

#application_controller.rb
post "/login" do
  if login(User, params[:login], params[:password])
    ...
    redirect to params[:redirect] || "/"
    ...
  end
end

尽管如此,我还是希望了解为什么中间件没有按预期执行,以及如何通过Rack中间件修复/存储此返回参数。