2015-11-18 4 views
2

Вот сценарий. Я использую ActionCable для сайта (назовем его www.example.com). Он отлично работает в dev, но как только я нажимаю его на Heroku, я получаю 302 ошибки для подключения к WebSocket.ActionCable, пользовательский домен Heroku и Cookies

Проблема, похоже, связана с тем, что у меня есть Heroku, используя собственный домен. Из-за этого, если я укажу WebSocket на wss://example.com, он дает мне 302, я предполагаю, потому что он перенаправляется на URL-адрес example.herokuapp.com?

Так что в свете этой проблемы я был вынужден вместо этого указать соединение с WebSocket на wss://example.herokuapp.com. Проблема, с которой я сейчас сталкиваюсь, заключается в том, что, поскольку это, по сути, новый домен, на который я указываю, файлы cookie с example.com не используются с example.herokuapp.com. Это означает, что example.herokuapp.com передает пустой файл cookie, который фактически устанавливается на example.com, который я использую для аутентификации.

Я проверил это, зарегистрировав cookie без знака (просто временно без знака для тестирования, не волнуйся о безопасности), а также установив этот файл cookie на сервере example.herokuapp.com. После этого он работал красиво.

Очевидно, что я не могу иметь кого-то идти на обоих сайтах просто установить проклятую печенье ...

То, что я хотел бы, чтобы найти способ, чтобы исправить первоначальную проблему, и быть в состоянии указать WebSocket на мой пользовательский домен wss://example.com и не нужно беспокоиться о проблемах с подписями файлов cookie. Это возможно?

Если нет, то какой был бы лучший способ установить cookie на домен example.herokuapp.com?

P.S. да, я посмотрел другие вопросы о ActionCable & Heroku, но ни один из них не имеет отношения к пользовательским доменам. Это один говорит о печенье решить эту проблему, но я не чувствую, как он будет работать с этим сценарием, так как они не являются теми же подобласти: Deploying Ruby on Rails app to Heroku while using Action Cable (Puma port listening)

Спасибо, что нашли время, чтобы помочь мне, ребята :)

[EDIT] Это похоже на этот вопрос здесь, но я получаю 302 не 503. Heroku error 503, webSockets on multiple domains

+0

Что было решение этой проблемы? Я сталкиваюсь с аналогичной проблемой – gwalshington

ответ

2

Таким образом, проблема, похоже, связана с тем, что запрос WebSocket не рассматривался как запрос WebSocket , а вместо этого обычный, не обновленный запрос. И это было перенаправлено путем разработки.

Я выяснил причину отсутствия заголовка HTTP_UPGRADE из-за CloudFlare. У них нет учетных записей на учетных записях Non-Enterprise (5000 + +). Я прочитал в другом вопросе SlackOverflow, что вы можете попросить CloudFlare включить его в своей учетной записи, но, скорее всего, этого не произойдет, пока они не начнут включать их для всех типов учетных записей.

Похоже, что единственным вариантом до тех пор, пока CloudFlare не включит WS, необходимо найти способ совместного использования/установки файлов cookie между пользовательским доменом и доменом Heroku. Я еще не нашел решения для этого, ожидая, когда Хероку выручит меня. Я буду обновлять этот ответ для будущих глогов, если я смогу получить решение для пользователей CloudFlare + Custom Domain Heroku + Action Cable.

0

Я столкнулся с той же проблемой, я также запускаю свой actioncable сервер на Heroku, с Cloudflare перед ним с включенным https.

я написал пост о том, как я рассматривал этот вопрос:

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

В принципе, я угробил печенье, и оказал подписанные user_id печенья в HTML вместо.

В моей 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 окр на любой Cloudflare инвалидов субдомен создали, например, ws.myapp.com.

При подключении к actioncable серверу, я вместо этого сделать что-то вроде:

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 

Есть несколько предостережений к этому хотя я бы сказал, что рендеринг секретности user_id в DOM менее безопасен, чем хранение в куки-браузерах, но 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 

 Смежные вопросы

  • Нет связанных вопросов^_^