viktor-shmigol / ng2-cable

Connect your Angular(2/4)/ionic(2/3) application with Rails ActionCable
https://ng2-cable-example.herokuapp.com
44 stars 14 forks source link

How to make rails action cable work with angular 2/4/6/8? Is the subscriber supposed to loop/ping? I'm losing authentication #23

Open venomoustoad opened 4 years ago

venomoustoad commented 4 years ago

I am trying to configure my action cable in rails with angular 2+ .

So I used the ng2cable to subscribe to the backend as follows:

Angular component Code

  this.ng2cable.subscribe(
    'ws://localhost:3000/cable?access-token=' +localStorage.getItem("accessToken")+ '&client=' + localStorage.getItem("client")+'&uid='+localStorage.getItem("uid"), 
    'NotificationChannel', 
    {}
  );
  this.broadcaster.on<string>('NotificationChannel').subscribe(
    message => {
      console.log(message);
    }
  );

My Rails connection.rb file

  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.get_email
    end
  private
      def find_verified_user
        access_token = request.query_parameters[:'access-token']
        client_id = request.query_parameters[:client]
        uid=  request.query_parameters[:uid]
        verified_user = User.find_by(email: uid)

        if verified_user && verified_user.valid_token?(access_token, client_id)
          verified_user
        else
          reject_unauthorized_connection
        end
      end
    end
  end

_notificationchannel.rb

  class NotificationChannel < ApplicationCable::Channel
    def subscribed
      stream_from "notification_channel"
    end
    def unsubscribed
    end
  end

Somewhere in my rails app controller:

ActionCable.server.broadcast "notification_channel", notification: 'this is a notification'

I see that the subscription works fine initially with the fresh tokens as the user is valid. But then, I see that on the server, the following code goes into a loop and tries to validate the tokens sent every few seconds as a part of the subscription. I thought websocket authentication was a one time thing and once the connection was established it would stream continuously.

Output (loops continuosly requiring validation everytime)

  Started GET "/cable?access-token=TJxxxxxxxxxxxxxxxxxxxsg&client=rkxxxxxxxxxxxxxxxxxxa5g&uid=my_email@gmail.com" for ::1 at 2019-10-21 18:09:26 +0530
  Remote IP: ::1
  Started GET "/cable/?access-token=TJxxxxxxxxxxxxxxxxxxxsg&client=rkxxxxxxxxxxxxxxxxxxa5g&uid=my_email@gmail.com" [WebSocket] for ::1 at 2019-10-21 18:09:26 +0530
  Successfully upgraded to WebSocket (REQUEST_METHOD: GET, HTTP_CONNECTION: Upgrade, HTTP_UPGRADE: websocket)
  An unauthorized connection attempt was rejected
  Failed to upgrade to WebSocket (REQUEST_METHOD: GET, HTTP_CONNECTION: Upgrade, HTTP_UPGRADE: websocket)
  Finished "/cable/?access-token=TJxxxxxxxxxxxxxxxxxxxsg-x_sg&client=rkPOGSNnVt97dUJ1hSDa5g&uid=my_email@gmail.com" [WebSocket] for ::1 at 2019-10-21 18:09:27 +0530
  Finished "/cable/?access-token=TJxxxxxxxxxxxxxxxxxxxsg-x_sg&client=rkxxxxxxxxxxxxxxxxxxa5g&uid=my_email@gmail.com" [WebSocket] for ::1 at 2019-10-21 18:09:27 +0530

Questions

  1. Is it normal that the subscribe action from the front end ends up pinging the server with the same request every few seconds (Started GET "/cable?access-token=TJxxxxxxxxxxxxxxxxxxxsg&client=rkxxxxxxxxxxxxxxxxxxa5g&uid=my_email@gmail.com")? I thought it would just have to authenticate for the first time and then the backend would push information through the web socket.
  2. Clearly , the "An unauthorized connection attempt was rejected" is happening since the token eventually gets outdated with repeated pinging of the same request from the subscriber. If this is an expected result, should I be refreshing the token with every ping? this seems to partially defeat the purpose of using a stream service? Please clarify my understanding.
  3. If this is the expected outcome, how do I send a new token every time as a part of the subscription?