Подтвердить что ты не робот

Отправить auth_token для аутентификации в ActionCable

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

    def connect
      #puts params[:auth_token]
      self.current_user = find_verified_user
      logger.add_tags 'ActionCable', current_user.name
   end

  end
end

Я не использую веб как конечную точку для кабеля действия, поэтому я хочу использовать auth_token для аутентификации. По умолчанию в кабеле действия используется идентификатор пользователя сеанса для аутентификации. Как передать параметры для подключения?

4b9b3361

Ответ 1

Мне удалось отправить токен аутентификации в качестве параметра запроса.

При создании моего потребителя в моем приложении javascript я передаю токен в URL-адресе кабельного сервера следующим образом:

wss://myapp.com/cable?token=1234

В моем кабельном соединении я могу получить этот token, обратившись к request.params:

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

    def connect
      self.current_user = find_verified_user
      logger.add_tags 'ActionCable', current_user.name
    end

    protected:
    def find_verified_user
      if current_user = User.find_by(token: request.params[:token])
        current_user
      else
        reject_unauthorized_connection
      end
    end
  end
end

Это явно не идеально, но я не думаю, что вы можете отправлять пользовательские заголовки при создании websocket.

Ответ 2

Ответ Пьера работает. Однако, это хорошая идея, чтобы быть явным о ожидании этих параметров в вашем приложении.

Например, в одном из ваших файлов конфигурации (например, application.rb, development.rb и т.д.) вы можете сделать это:

config.action_cable.mount_path = '/cable/:token'

А затем просто получить доступ к нему из вашего класса Connection с помощью:

request.params[:token]

Ответ 3

К сожалению, для соединений с веб-сайтами дополнительные заголовки и пользовательские не поддерживаются 1 большинством 2 клиентов и серверов websocket. Таким образом, возможны следующие варианты:

  • Прикрепите в качестве параметра URL и проанализируйте его на сервере

    path.to.api/cable?token=1234
    
    # and parse it like
    request.params[:token]
    

Против. Он может быть уязвимым, поскольку он может оказаться в журналах и системной информации процесса доступным для других, имеющих доступ к серверу, более здесь

Решение: зашифруйте токен и присоедините его, поэтому, даже если его можно увидеть в журналах, он не будет иметь никакой цели до его дешифрования.

  • Прикрепите JWT в одном из разрешенных параметров.

Клиентская сторона:

# Append jwt to protocols
new WebSocket(url, existing_protocols.concat(jwt))

Я создал библиотеку JS action-cable-react-jwt для React и React-Native, которая просто делает это. Не стесняйтесь использовать его.

Серверная сторона:

# get the user by 
# self.current_user = find_verified_user

def find_verified_user
  begin
    header_array = self.request.headers[:HTTP_SEC_WEBSOCKET_PROTOCOL].split(',')
    token = header_array[header_array.length-1]
    decoded_token = JWT.decode token, Rails.application.secrets.secret_key_base, true, { :algorithm => 'HS256' }
    if (current_user = User.find((decoded_token[0])['sub']))
      current_user
    else
      reject_unauthorized_connection
    end
  rescue
    reject_unauthorized_connection
  end
end

1 Большинство API-интерфейсов Websocket (включая Mozilla) аналогичны следующим:

Конструктор WebSocket принимает один обязательный и один необязательный Параметр:

WebSocket WebSocket(
  in DOMString url,
  in optional DOMString protocols
);

WebSocket WebSocket(
  in DOMString url,
  in optional DOMString[] protocols
);

url

URL-адрес для подключения; это должен быть URL-адрес, по которому Сервер WebSocket ответит.

protocols Необязательный

Либо одна строка протокола, либо массив строк протокола. Эти строки используются для указания под-протоколов, так что один сервер может реализовать несколько под-протоколов WebSocket (например, вы можете хотите, чтобы один сервер мог обрабатывать различные типы взаимодействий в зависимости от указанного протокола). Если вы не укажете протокол string, предполагается пустая строка.

2 Есть всегда excpetions, например, этот node.js lib ws позволяет создавая пользовательские заголовки, поэтому вы можете использовать обычный заголовок Authorization: Bearer token и анализировать его на сервере, но и клиент и сервер должны использовать ws.

Ответ 4

Также можно передать токен аутентификации в заголовках запроса, а затем проверить соединение, обратившись к хешу request.headers. Например, если токен аутентификации был указан в заголовке под названием "X-Auth-Token", а ваша модель пользователя имеет поле auth_token, которое вы могли бы сделать:

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

    def connect
      self.current_user = find_verified_user
      logger.add_tags 'ActionCable', current_user.id
    end

    protected

    def find_verified_user
      if current_user = User.find_by(auth_token: request.headers['X-Auth-Token'])
        current_user
      else
        reject_unauthorized_connection
      end
    end
  end
end

Ответ 5

Что касается безопасности Ответ Pierre: если вы используете протокол WSS, который использует SSL для шифрования, то принципы отправки защищенных данных должны быть такими же, как для HTTPS. При использовании SSL параметры строки запроса зашифровываются, а также тело запроса. Поэтому, если в HTTP API вы отправляете какой-либо токен через HTTPS и считаете его безопасным, тогда он должен быть таким же для WSS. Просто помните, что то же, что и для HTTPS, не отправляйте учетные данные, такие как пароль через параметры запроса, поскольку URL-адрес запроса может быть зарегистрирован на сервере и, таким образом, сохранен с вашим паролем. Вместо этого используйте такие вещи, как маркеры, выпущенные сервером.

Также вы можете проверить это (это в основном описывает что-то вроде проверки подлинности JWT и проверки IP-адреса): https://devcenter.heroku.com/articles/websocket-security#authentication-authorization.

Ответ 6

В случае, если кто-либо из вас захочет использовать ActionCable.createCustomer. Но у меня есть возобновляемый токен, как и я:

const consumer = ActionCable.createConsumer("/cable")
const consumer_url = consumer.url
Object.defineProperty(
  consumer, 
  'url', 
  {
      get: function() { 
        const token = localStorage.getItem('auth-token')
        const email = localStorage.getItem('auth-email')
        return consumer_url+"?email="+email+"&token="+token
      }
  });
return consumer; 

Затем в случае потери связи он будет открыт с новым новым токеном.