适用于Apache的rails app的OpenID

我正在尝试通过Google帐户集成简单的OpenID身份validation。 我正在使用omniauth gem并在我的本地开发系统上(Win7,ruby 1.8.7-p302,rails 2.3.8,omniauth 0.1.5)一切正常。

当我将它部署到我的主机(HostGator)时,问题就显示出来了。 应用程序(mongrel)从端口12002开始,通过HostGator的cPanel,它被配置为从一个子域重写:

RewriteCond %{HTTP_HOST} ^subdomain.mycompany.com$ [OR] RewriteCond %{HTTP_HOST} ^www.subdomain.mycompany.com$ RewriteRule ^(.*)$ "http\:\/\/127\.0\.0\.1\:12002\/$1" [P,L] 

当浏览器进入/ auth / open_id时,它会被重定向到Google进行授权,但它的return_to地址是subdomain.mycompany.com:12002,这当然是不正确的,因为Apache不会在12002上监听。我已经设法修改了OmniAuth :: Strategies :: OpenID和Rack :: OpenID所以他们在没有端口BUT的情况下组装地址现在在用户访问确认后的最后阶段如果落入:

 Routing Error No route matches "/403.shtml" with {:method=>:get} 

我想问题是我的网站的地址被编码(某种哈希)在其他授权请求参数,以避免

端口问题是由于RACK请求计算端口的方式。 这是补丁

 require 'rack/utils' module Rack class Request def port if host_with_port =~ /:(\d+)$/ $1.to_i else standard_port end end # Returns the standard \port number for this request's protocol. def standard_port case protocol when 'https://' then 443 else 80 end end # Returns 'https://' if this is an SSL request and 'http://' otherwise. def protocol ssl? ? 'https://' : 'http://' end # Is this an SSL request? def ssl? @env['HTTPS'] == 'on' || @env['HTTP_X_FORWARDED_PROTO'] == 'https' end end end 

这是rails ActionController :: Request计算端口的方式。

希望这可以帮助

好…

403错误是因为托管安全规则非常严格,因此谷歌的OpenID响应(足够长的可疑)被拒绝了。 通过托管支持解决。

要解决return_to参数中的端口号问题(由freiwillen解决),我已经创建了以下(猴子路径)初始化器:

 module OmniAuth module Strategies # OmniAuth strategy for connecting via OpenID. This allows for connection # to a wide variety of sites, some of which are listed [on the OpenID website](http://openid.net/get-an-openid/). class OpenID protected def callback_url uri = URI.parse(request.url) uri.path += '/callback' # by KirylP: to overcome hosting subdomain forwarding to rails port uri.port = '' if request.env.has_key? 'HTTP_X_FORWARDED_SERVER' uri.to_s end end end end module Rack class OpenID SERVER_PORT_TO_AVOID = 12002 private def realm_url(req) url = req.scheme + "://" url << req.host scheme, port = req.scheme, req.port if scheme == "https" && port != 443 || scheme == "http" && port != 80 url << ":#{port}" if port != SERVER_PORT_TO_AVOID # KirylP end url end end end module OpenID class Consumer def complete(query, current_url) message = Message.from_post_args(query) current_url.sub!(":#{Rack::OpenID::SERVER_PORT_TO_AVOID}", '') # KirylP mode = message.get_arg(OPENID_NS, 'mode', 'invalid') begin meth = method('complete_' + mode) rescue NameError meth = method(:complete_invalid) end response = meth.call(message, current_url) cleanup_last_requested_endpoint if [SUCCESS, CANCEL].member?(response.status) cleanup_session end return response end end end 

我希望有人会提出更优雅的解决方案。

在最新版本的Omniauth(0.2.0.beta4)中,您可以full_host指定为配置选项 ,并将其设置为在每个请求时进行评估,或者仅使用固定值。

示例(rails):

 ActionController::Dispatcher.middleware.use OmniAuth::Builder do store = Rails.env.development? ? OpenID::Store::Filesystem.new("#{Rails.root}/tmp") : nil provider :open_id, store, :name => 'google', :identifier => 'https://www.google.com/accounts/o8/id', :scope => 'email' if Rails.env.production? configure do |config| config.full_host = lambda do |env| req = Rack::Request.new(env) "#{req.scheme}://#{req.host}" # req.host strips port number end end end end