Search code examples
angularjslaravelwebsocketautobahnratchet

Building realtime app using Laravel and Latchet websocket


I'm building a closed app (users need to authenticate in order to use it). I'm having trouble in identifying the currently authenticated user from my Latchet session. Since apache does not support long-lived connections, I host Latchet on a separate server instance. This means that my users receive two session_id's. One for each connection. I want to be able to identify the current user for both connections.

My client code is a SPA based on AngularJS. For client WS, I'm using the Autobahn.ws WAMP v1 implementation. The ab framework specifies methods for authentication: http://autobahn.ws/js/reference_wampv1.html#session-authentication, but how exactly do I go about doing this?

Do I save the username and password on the client and retransmit these once login is performed (which by the way is separate from the rest of my SPA)? If so, won't this be a security concearn?

And what will receive the auth request server side? I cannot find any examples of this...

Please help?

P.S. I do not have reputation enough to create the tag "Latchet", so I'm using Ratchet (which Latchet is built on) instead.


Solution

  • Create an angularjs service called AuthenticationService, inject where needed and call it with:

    AuthenticationService.check('login_name', 'password');
    

    This code exists in a file called authentication.js. It assumes that autobahn is already included. I did have to edit this code heavily removing all the extra crap I had in it,it may have a syntax error or two, but the idea is there.

    angular.module(
      'top.authentication',
      ['top']
    )
    
    .factory('AuthenticationService', [ '$rootScope', function($rootScope) {
        return {
            check: function(aname, apwd) {
                  console.log("here in the check function");
                  $rootScope.loginInfo = { channel: aname, secret: apwd };
                  var wsuri = 'wss://' + '192.168.1.11' + ':9000/';
                  $rootScope.loginInfo.wsuri = wsuri;
                  ab.connect(wsuri,
                      function(session) {
                          $rootScope.loginInfo.session = session;
                          console.log("connected to " + wsuri);
                          onConnect(session);
                      },
                      function(code,reason) {
                          $rootScope.loginInfo.session = null;
                          if ( code == ab.CONNECTION_UNSUPPORTED) {
                              console.log(reason);
                          } else {
                              console.log('failed');
                              $rootScope.isLoggedIn = 'false';
                          }
                      }
                  );
    
                  function onConnect(sess) {
                      console.log('onConnect');
                      var wi = $rootScope.loginInfo;
                      sess.authreq(wi.channel).then(
                        function(challenge) {
                            console.log("onConnect().then()");
                            var secret = ab.deriveKey(wi.secret,JSON.parse(challenge).authextra);
                            var signature = sess.authsign(challenge, secret);
                            sess.auth(signature).then(onAuth, ab.log);
                        },ab.log
                      );
                  }
    
                  function onAuth(permission) {
                      $rootScope.isLoggedIn = 'true';
                      console.log("authentication complete");
                      // do whatever you need when you are logged in..
                  }
            }
        };
        }])
    

    then you need code (as you point out) on the server side. I assume your server side web socket is php coding. I can't help with that, haven't coded in php for over a year. In my case, I use python, I include the autobahn gear, then subclass WampCraServerProtocol, and replace a few of the methods (onSessionOpen, getAuthPermissions, getAuthSecret, onAuthenticated and onClose) As you can envision, these are the 'other side' of the angular code knocking at the door. I don't think autobahn supports php, so, you will have to program the server side of the authentication yourself.

    Anyway, my backend works much more like what @oberstat describes. I establish authentication via old school https, create a session cookie, then do an ajax requesting a 'ticket' (which is a temporary name/password which i associate with the web authenticated session). It is a one use name/password and must be used in a few seconds or it disappears. The point being I don't have to keep the user's credentials around, i already have the cookie/session which i can create tickets that can be used. this has a neat side affect as well, my ajax session becomes related to my web socket session, a query on either is attributed to the same session in the backend.

    -g