繁体   English   中英

为什么我在Rails应用程序中使用force_ssl获得无限重定向循环?

[英]Why am I getting infinite redirect loop with force_ssl in my Rails app?

我希望我的API控制器使用SSL,所以我在我的nginx.conf中添加了另一个listen指令

upstream unicorn {
  server unix:/tmp/unicorn.foo.sock fail_timeout=0;
}

server {
  listen 80 default deferred;
  listen 443 ssl default;
  ssl_certificate /etc/ssl/certs/foo.crt;
  ssl_certificate_key /etc/ssl/private/foo.key;

  server_name foo;
  root /var/apps/foo/current/public;

  try_files $uri/system/maintenance.html $uri/index.html $uri @unicorn;

  location @unicorn {
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_redirect off;
    proxy_pass http://unicorn;
  }

  error_page 502 503 /maintenance.html;
  error_page 500 504 /500.html;
  keepalive_timeout 5;
}

它通过nginx conftest没有任何问题。 我还在我的ApiController中添加了一个force_ssl指令

class ApiController < ApplicationController
  force_ssl if Rails.env.production?

  def auth
    user = User.authenticate(params[:username], params[:password])
    respond_to do |format|
      format.json do
        if user
          user.generate_api_key! unless user.api_key.present?
          render json: { key: user.api_key }
        else
          render json: { error: 401 }, status: 401
        end
      end
    end
  end

  def check
    user = User.find_by_api_key(params[:api_key])
    respond_to do |format|
      format.json do
        if user
          render json: { status: 'ok' }
        else
          render json: { status: 'failure' }, status: 401
        end
      end
    end
  end
end

当我没有使用SSL时工作得很好,但现在当我尝试curl --LI http://foo/api/auth.json时 - 我curl --LI http://foo/api/auth.json ,我被正确地重定向到https ,但后来我继续被重定向到http://foo/api/auth以无限重定向循环结束。

我的路线很简单

get "api/auth"
get "api/check"

我在Ruby 1.9.2上使用Rails 3.2.1,nginx为0.7.65

您没有转发有关此请求是否是HTTPS终止请求的任何信息。 通常,在服务器中,“ssl on;” 指令将设置这些标头,但您正在使用组合块。

Rack(和force_ssl)通过以下方式确定SSL:

  • 如果请求进入端口443(这很可能不会从nginx传回Unicorn)
  • 如果ENV ['HTTPS'] ==“on”
  • 如果X-Forwarded-Proto标头==“HTTPS”

有关完整故事,请参阅force_ssl源代码

由于您使用的是组合块,因此您需要使用第三种形式。 尝试:

proxy_set_header X-Forwarded-Proto $scheme;

根据nginx文档在您的服务器或位置块中。

当您进入端口80请求时,这会将标头设置为“http”,并在您进入443请求时将其设置为“https”。

尝试在你的nginx location @unicorn块中设置这个指令:

proxy_set_header X-Forwarded-Proto https;

我有同样的问题,并调查Rack中间件处理程序(不是force_ssl但类似)我可以看到它期望设置标头以确定请求是否已被nginx处理为SSL。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM