2015-11-18 116 views
2

以下是該場景。我爲一個網站使用ActionCable(我們稱之爲www.example.com)。它在開發中非常完美,但是一旦我將它推到Heroku中,WebSocket連接就會出現302錯誤。ActionCable,Heroku自定義域名和Cookie

這個問題似乎源於我使用自定義域Heroku的事實。因此,如果我將WebSocket指向wss://example.com,它會給我一個302,我假設它是因爲它被重定向到example.herokuapp.com url?

所以鑑於這個問題,我不得不將WebSocket連接指向wss://example.herokuapp.com。我現在遇到的問題是,因爲它基本上是我指向的新域,所以來自example.com的cookie不與example.herokuapp.com共享。這意味着example.herokuapp.com正在傳遞一個實際在example.com上設置的用於身份驗證的空cookie。

我通過記錄未簽名的cookie(只是暫時未簽名進行測試,不要錯過安全性),並在example.herokuapp.com服務器上設置該cookie來驗證這是問題。之後,它工作得很漂亮。

很顯然,我不能一個人去這兩個網站只是設置一個該死的餅乾......

我會愛是找到一種方法來解決原來的問題,並能夠在指向網頁套接字我的自定義域爲wss://example.com,無需擔心cookie簽名問題。這可能嗎?

如果不是,那麼在example.herokuapp.com域上設置cookie的最佳方法是什麼?

P.S.是的,我看過其他關於ActionCable & Heroku的問題,但似乎沒有處理自定義域名。約一個cookie解決此一一談話,但我不覺得它會跟這種情況下工作,因爲他們是不一樣的子域:Deploying Ruby on Rails app to Heroku while using Action Cable (Puma port listening)

感謝您抽出寶貴時間來幫助我的傢伙:)

[編輯]這似乎非常相似,在這裏這個問題,但我發現了一個302而不是503 Heroku error 503, webSockets on multiple domains

+0

什麼是解決這個?我遇到了類似的問題 – gwalshington

回答

2

所以,問題似乎從事實的WebSocket請求沒有被當作WebSocket的請求,幹,而是一個正常的,未升級的請求。這樣的設計正在重新定向。

我想出了沒有任何HTTP_UPGRADE頭的原因是因爲CloudFlare。他們沒有在非企業帳戶上啓用WebSockets($ 5000 +)。我已閱讀其他SlackOverflow問題,您可以要求CloudFlare在您的帳戶中啓用它,但最有可能在他們開始爲所有帳戶類型啓用它之前不會發生。

似乎在CloudFlare啓用WS之後,唯一的其他選擇是找到一種方法來在自定義域和Heroku域之間共享/設置Cookie。我還沒有找到解決方案,等待Heroku幫我解決問題。如果我可以獲得CloudFlare +自定義域Heroku + Action Cable用戶的解決方案,我會針對未來可能的Google員工更新此答案。

0

我跑到完全相同的問題,我也在Heroku上運行我的actioncable服務器,使用https啓用Cloudflare。

我寫了,我怎麼解決這個問題後:

https://herenow.pw/article/rails-actioncable-on-different-domain/

基本上,我拋棄餅乾,在HTML渲染簽署user_id cookie而不是。

在我的ApplicationController我寫了下面:signed_user_idhelper_method

def signed_user_id 
    @signed_user_id ||= crypt.encrypt_and_sign(current_user.id) if current_user 
    end 

    def crypt 
    @crypt ||= ActiveSupport::MessageEncryptor.new(
     Rails.application.secrets.secret_key_base, 
    ) 
    end 

某處的佈局,我作出以下JS片段:

<script type="text/javascript"> 
    window.AppConfig = { 
    WEBSOCKET_HOST: "<%= ENV['WEBSOCKET_HOST'] %>", 
    WEBSOCKET_PATH: "<%= ActionCable.server.config.mount_path %>", 
    <% if user_signed_in? %> 
    WEBSOCKET_USER_ID_SECRET: "<%= signed_user_id %>", 
    <% end %> 
    } 
</script> 

設置WEBSOCKET_HOST ENV到任何的CloudFlare禁用子網域已創建,例如,ws.myapp.com。驗證我做了以下連接時

var protocol = window.location.protocol === "https:" ? "wss://" : "ws://"; 
var host  = window.AppConfig.WEBSOCKET_HOST || window.location.host; 
var path  = window.AppConfig.WEBSOCKET_PATH || '/cable'; 
var userId = window.AppConfig.WEBSOCKET_USER_ID_SECRET; 
var url  = protocol + host + path; 

if(userId) { 
    url += '?user_id=' + encodeURIComponent(userId); 
} 

App.cable = ActionCable.createConsumer(url); 

然後我actioncable服務器上:

module ApplicationCable 
    class Connection < ActionCable::Connection::Base 
    identified_by :current_user 

    def connect 
     self.current_user = find_verified_user 
    end 

    protected 

    def find_verified_user 
     if current_user = User.find_by(id: user_id) 
     current_user 
     else 
     reject_unauthorized_connection 
     end 
    end 

    private 

    def user_id 
     signed_user_id = request.params.fetch(:user_id) 

     crypt.decrypt_and_verify(signed_user_id) 
    end 

    def crypt 
     @crypt ||= ActiveSupport::MessageEncryptor.new(
     Rails.application.secrets.secret_key_base, 
    ) 
    end 
    end 
end 

有一些注意事項這個

當連接到actioncable服務器,我不是這樣做盡管如此,我認爲在DOM中渲染user_id祕密不如在瀏覽器cookie中存儲安全,但是IMO,如果擔心安全問題,我們應該完全轉移到基於令牌的身份驗證方案。

0

我一直在用完全相同的設置掙扎。如果您使用的是devise,則可以從env['warden'].user.id(僅在您成功登錄後纔會設置)而不是從簽名的cookie中獲取用戶標識。

即在你的連接做這樣的事情:

module ApplicationCable 
    class Connection < ActionCable::Connection::Base 
    identified_by :current_user 

    def connect 
     self.current_user = find_verified_user 
    end 

    private 
     def find_verified_user 
     # if verified_user = User.find_by(id: cookies.signed[:user_channel_key]) 
     if verified_user = User.find_by(id: env['warden'].user.id) 
      verified_user 
     else 
      reject_unauthorized_connection 
     end 
     end 
    end 
end