1

我为 rails 创建了一个自定义中间件,它将拦截所有请求并确保它来自授权 IP,否则它应该提示输入基本的 http auth 用户/名称密码。

这是目前的样子:

require 'net/http'

class AuthorizeEnvironment
  def initialize(app)
    @app = app
  end

  def call(env)
    if AppConstants.approved_doximity_ips.include?(env["REMOTE_ADDR"])
      @app.call(env)
    elsif authorized?(env)
      @app.call(env)
    else
      [403, {"Content-Type" => "text/html"}, ["Not Authorized on this environment."]]
    end
  end

  def authorized?(env)
    @auth ||= Rack::Auth::Basic::Request.new(env)
    @auth.provided? && @auth.basic? && @auth.credentials && @auth.credentials == ['username', 'password']
  end
end

这段代码的问题是我似乎找不到在浏览器上触发 http auth 窗口的方法。我对此进行了审查但没有看到任何明显的迹象表明这是如何完成的。

你能指出我正确的方向吗?

4

3 回答 3

5

Rack::Auth::Basic直接使用并为自己保存了验证部分:

class BasicAuth
  def initialize(app)
    @app = app
  end

  def call(env)
    if env["PATH_INFO"] == '/supersecret' # Any condition here
      auth = Rack::Auth::Basic.new(@app) do |u, p|
        u == username && p == password
      end
      auth.call env
    else
      @app.call env
    end
  end

  def username
    ENV["username"]
  end

  def password
    ENV["password"]
  end
end

```

于 2013-06-20T08:55:31.060 回答
1

我没有测试你的代码,但看起来你用 403 回复,意思是“禁止”。即当前登录的用户没有访问该资源的权限。

来自 RFC ( http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html )

服务器理解请求,但拒绝执行。授权将无济于事,并且不应重复请求。如果请求方法不是 HEAD 并且服务器希望公开请求未完成的原因,它应该在实体中描述拒绝的原因。如果服务器不希望向客户端提供此信息,则可以使用状态代码 404(未找到)来代替。

相反,您需要使用 401,并且仅当当前登录的用户无法访问资源时才使用 403 回复。

于 2013-05-16T01:23:29.653 回答
1

您需要提供一个WWW-Authenticate标题。

我假设,在你的else,你会做:

[401, {'WWW-Authenticate' => 'Basic realm="Application"', "Content-Type" => "text/html"}, ["Not Authorized on this environment."]]
于 2013-10-15T20:44:56.420 回答