Search code examples
phpnode.jsredispublish-subscribeautobahn

Real time chat in PHP +Redis +Pub/Sub +WebSockets (+NodeJS)


I want to develop real time chat with channels and these are my needs:

  • PHP backend to manage site
  • Redis as session and data primary storage
  • Pub/Sub to send messages only to channel's interested users
  • one WebSocket connection with which the messages will be send and received.
  • (optional) NodeJS to use great npm packages like timesync or socket.io

I see two different architectures to achieve this:

  • with Socket.io

    socket.io

  • with Crossbar.io

    crossbar.io

These are my questions:

  1. Which architecture I should choose and why?
  2. The key is the user id cannot be obtained from client, because it can be malformed. So in the first architecture I think on every socket message I should attach PHPSESSID value from cookie and on sever-side retrieve PHP session from Redis. Am I right or there is better way to get user id?
  3. I wonder if getting user id in second architecture can be done differently?

Edit:

I choosed Crossbar.io, cause it is very powerful and allows to communicate many different language applications in real time. After studying examples, I come up with this:

  • On every login user have generated secret key in database.

  • PHP client (Thruway) connect to Crossbar server and register custom WAMP-CRA authenticator

  • User's browser connect to Crossbar server and is challenged. Secret and auth_id (user id) are loaded from DB with page load, so it can accomplish challenge and send response.

  • PHP authenticator search in DB for user with provided secret and id equal to auth_id. If there is, then it successfully authenticate session. Now we can trust that auth_id is real user id.

These are my question:

  1. How I can get auth_id on subscribe?

  2. I also added cookie authentication and browser is remembered after authentication. But when I look in Chrome DevTools there is any cookie nor value in local storage. Even after clearing cache my browser is still remember by Crossbar. I wonder how it is possible?

Edit2:

Maybe I was misunderstood, but the main question was choosing appropriate architecture and getting trusted user id. There was no attention so I awarded bounty and after that I was downvoted. I read a lot about real-time apps and finally decided to use Crossbar.io, so I edited question to be related to it. Then people started upvoting, proposing another architectures, but not really answering my questions. After all I managed to do it myself and presented my answer.


Solution

  • About getting user id:

    Every real-time chat examples which I saw, was getting id from client. It is unsafe, because client easily can manipulate it, so I needed to find another method. After reading WAMP specs I finally figured out that I have to authenticate user not only in app, but also in Crossbar.io. I choosed the dynamic WAMP-CRA method and implemented as following:

    • PHP app connect to Crossbar server and register custom authenticator (similar to example)
    • After user login in app there is generated secret key for him and saved in database. After logout, key is destroyed.
    • Workflow:

      1. Every loaded page contain user id and secret key loaded from db:

        <script>
            auth_id = '<?php echo $user->id ?>';
            secret_key = '<?php echo $user->secret_key ?>';
        </script>
        
      2. User browser connect to Crossbar.io server and get response with challenge from custom authenticator.
      3. It calculate signature using key and send along with auth_id to Crossbar.io server
      4. Authenticator gets from DB secret for provided auth_id and calculate signature. Then signatures are compared and if they are equal then authentication is successfull.
      5. Now auth_id contain user id and we can trust its value. Now you can refer section 'How I can get auth_id on subscribe?'.

    Answers:

    How I can get auth_id on subscribe?

    By default publishers and subscribers does not have any knowledge about each other, but documentation show there is option to change it by configuring disclosure of caller identity. Then you can get auth_id from callback details:

    • PHP:

      $onEvent = function ($args, $argsKw, $details, $publicationId) use ($session) {
          $auth_id = $details->publisher_authid;
          ...
      }
      $session->register('com.example.event', $onEvent);
      
    • JS:

      function on_event(args, kwargs, details) {
          auth_id = details['publisher_authid'];
          ...
      }
      session.subscribe('com.example.event', on_event);
      

    I also added cookie authentication and browser is remembered after authentication. But when I look in Chrome DevTools there is any cookie nor value in local storage. Even after clearing cache my browser is still remember by Crossbar. I wonder how it is possible?

    First of all, clearing cache and hard reload does not remove cookies. When I was asking this question there was any cookie presented, but today I can see cbtid: cookies There was Chrome update two days ago, so maybe this was caused by bug in previous version.