Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

Cover image for QR login like whatsapp using webocket php
Sahil kashyap
Sahil kashyap

Posted on • Edited on

     

QR login like whatsapp using webocket php

QR login using websocket in laravel

  • QR test page in incognito mode
    QR test page in incognito mode

  • When QR scanned
    When QR scanned successfully

  • Things happening in the websocket
    WS console

package used:

  1. cboden/ratchet

Our app and websocket are on different port.
Let's setup command to run the websocket

<?phpnamespaceApp\Console\Commands;useIlluminate\Console\Command;useRatchet\Server\IoServer;useRatchet\Http\HttpServer;useRatchet\WebSocket\WsServer;useApp\Http\Controllers\WebSocketController;useReact\EventLoop\Factory;useReact\Socket\SecureServer;useReact\Socket\Server;classWebSocketServerextendsCommand{/**     * The name and signature of the console command.     *     * @var string     */protected$signature='websocket:init';/**     * The console command description.     *     * @var string     */protected$description='Initializing Websocket server to receive and manage connections';/**     * Create a new command instance.     *     * @return void     */publicfunction__construct(){parent::__construct();}/**     * Execute the console command.     *     * @return mixed     */publicfunctionhandle(){//for local// $this->forlocal();//for prod server$this->forprodserver();}publicfunctionforlocal(){$server=IoServer::factory(newHttpServer(newWsServer(newWebSocketController())),8090);$server->run();}publicfunctionforprodserver(){$loop=Factory::create();$webSock=newSecureServer(newServer('0.0.0.0:8090',$loop),$loop,array('local_cert'=>'/etc/letsencrypt/live/test.tv.com/fullchain.pem',// path to your cert'local_pk'=>'/etc/letsencrypt/live/test.tv.com/privkey.pem',// path to your server private key'allow_self_signed'=>true,// Allow self signed certs (should be false in production)'verify_peer'=>false));// Ratchet magic$webServer=newIoServer(newHttpServer(newWsServer(newWebSocketController())),$webSock);$loop->run();}}
Enter fullscreen modeExit fullscreen mode

Let's setup the routes
web.php

<?phpRoute::get('/qrtesting', 'Admin\QRLoginTwoController@qrtesting');Route::post('web/loginws', 'Admin\QRLoginTwoController@loginWS');Route::get('/qrscanner', 'Admin\QRLoginTwoController@qrscanner2');
Enter fullscreen modeExit fullscreen mode

Controller

<?phpuseApp\Http\Controllers\Controller;useIlluminate\Http\Request;useIlluminate\Support\Facades\Auth;classQRLoginTwoControllerextendsController{publicfunctionqrtesting(){returnview('frontend.qrtesting');}publicfunctionqrscanner2(){if(Auth::check()){$login=true;returnview('frontend.qrscanner2',compact('login'));}returnredirect()->route('home');}publicfunctionloginWS(Request$request){$key=$request['key'];if(empty($key)){$return=array('status'=>2,'msg'=>'key not provided');returnresponse()->json($return,200);}$userid=UnHashUserID($key);try{$user=Auth::loginUsingId($userid,true);$return=array('status'=>1,'msg'=>'success','jwt'=>1,'user'=>$user);returnresponse()->json($return,200);}catch(Exception$exception){returnresponse()->json(['status'=>2,'success'=>false,'message'=>'Some Error occured','error'=>$exception->getMessage(),'response_code'=>200,],200);}}}?>
Enter fullscreen modeExit fullscreen mode

WebSocketController.php

<?phpnamespaceApp\Http\Controllers;useIlluminate\Support\Str;useRatchet\MessageComponentInterface;useRatchet\ConnectionInterface;classWebSocketControllerextendsControllerimplementsMessageComponentInterface{private$connections=[];private$clients;private$cache;publicfunction__construct(){$this->clients=new\SplObjectStorage();// memory cache$this->cache=array();}publicfunctionmulticast($msg){foreach($this->clientsas$client)$client->send($msg);}publicfunctionsend_to($to,$msg){if(array_key_exists($to,$this->clientids))$this->clientids[$to]->send($msg);}/**     * When a new connection is opened it will be passed to this method     * @param  ConnectionInterface $conn The socket/connection that just connected to your application     * @throws \Exception     */functiononOpen(ConnectionInterface$conn){$this->clients->attach($conn);echo"New connection! ({$conn->resourceId})\n";}/**     * This is called before or after a socket is closed (depends on how it's closed).  SendMessage to $conn will not result in an error if it has already been closed.     * @param  ConnectionInterface $conn The socket/connection that is closing/closed     * @throws \Exception     */functiononClose(ConnectionInterface$conn){unset($this->cache[$conn->resourceId]);$this->clients->detach($conn);echo"Connection{$conn->resourceId} has disconnected\n";$this->clients->detach($conn);}/**     * If there is an error with one of the sockets, or somewhere in the application where an Exception is thrown,     * the Exception is sent back down the stack, handled by the Server and bubbled back up the application through this method     * @param  ConnectionInterface $conn     * @param  \Exception $e     * @throws \Exception     */functiononError(ConnectionInterface$conn,\Exception$e){echo"An error has occurred:{$e->getMessage()}\n";$conn->close();}/**     * Triggered when a client sends data through the socket     * @param  \Ratchet\ConnectionInterface $conn The socket/connection that sent the message to your application     * @param  string $msg The message received     * @throws \Exception     */functiononMessage(ConnectionInterface$from,$msg){$numRecv=count($this->clients)-1;echosprintf('Connection %d sending message "%s" to %d other connection%s'."\n",$from->resourceId,$msg,$numRecv,$numRecv==1?'':'s');$obj=json_decode($msg);$type=$obj->type;if($type=='client'){switch($obj->step){case0:// echo "\n inside client,step0 \n";$token=$obj->token;$theuuid=UnHashUserID($token);//todo add jwt with 2minutes of token$tokenexist=array_key_exists($theuuid,$this->cache);if($tokenexist){echo"\n token exist ya\n";$ee=$this->cache[$theuuid];// print_r($ee);if($ee['status']=='0'){$this->cache[$theuuid]['status']=1;$this->cache[$theuuid]+=['child'=>$from];$myArray2[]=(object)['step'=>1];$Scan=new\SplObjectStorage();$Scan->code=0;$Scan->data=$myArray2[0];$Scan->msg="Scan code successfully";$this->cache[$theuuid]['parent']->send(json_encode($Scan));$ready2=new\SplObjectStorage();$ready2->code=0;$ready2->data=$myArray2[0];$ready2->msg="Ready";$from->send(json_encode($ready2));};}else{echo"token doesn't exsit";}break;case1:$myArray3[]=(object)['step'=>2];$myArray4[]=(object)['step'=>2,'username'=>$obj->username];foreach($this->cacheas$v){if($v['child']==$from){// $token updateSessionToken;$ready3=new\SplObjectStorage();$ready3->code=0;$ready3->data=$myArray4[0];$ready3->msg="Already logged in";if(array_key_exists("parent",$v)){}$v['parent']->send(json_encode($ready3));}}$ready=new\SplObjectStorage();$ready->code=0;$ready->data=$myArray3[0];$ready->msg="Login successful";$from->send(json_encode($ready));}}elseif($type=='server'){// echo "hello inside server";//to get the QR logoswitch($obj->step){case0:$uuid=$from->resourceId;//Str::random(30);echo$uuid;$token=HashUserID($uuid);// echo $token;$this->cache[$uuid]=['status'=>0,'parent'=>$from];$url=url('');// Get the current url// dd($url);$http=$url.'?t='.$token;// Verify the url method of scanning code$myArray[]=(object)['step'=>0,'url'=>$http];$ready=new\SplObjectStorage();$ready->code=0;$ready->data=$myArray[0];$ready->msg="Ready";$from->send(json_encode($ready));break;}}}}
Enter fullscreen modeExit fullscreen mode

Let's generate the QR code:qrtesting.blade.php

<!DOCTYPE HTML><html><head><scriptsrc="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script><scriptsrc="../frontend/qr/jquery.qrcode-0.11.0.min.js"></script><scripttype="text/javascript">$(document).ready(function(){initiate();});functioninitiate(){if("WebSocket"inwindow){varbase=window.location.hostname;// var ws = new WebSocket('wss://'+base+':8090');varws=newWebSocket('wss://'+base+':8090');console.log(ws);ws.onopen=function(){ws.send(JSON.stringify({type:"server",code:0,step:0}));};ws.onmessage=function(evt){constdata=JSON.parse(event.data);//console.log("datafromservver",data);conststep=data.data&&data.data.step;if(step===0){//Generate QR Code and show to user.$("#qrcode").qrcode({"width":100,"height":100,"text":data.data.url});console.log("QR code generated successfully");}elseif(step===2){const{username,token}=data.data;//localStorage.setItem(TOKEN_KEY, token);$("#qrcode").html("");ws.close();//alert(username);is_loginfun(username);}};ws.onclose=function(){console.log("Connection is closed...");};}else{alert("WebSocket NOT supported by your Browser!");}}// Check whether the login has been confirmedfunctionis_loginfun(param){varkey=param;console.log("is_login called");$.ajax({type:"POST",dataType:"json",url:"web/loginws",data:{key:key,"_token":"<?php echo  csrf_token() ?>"},headers:{'x-csrf-token':'<?php echo  csrf_token() ?>'},success:function(data){if(data.status==1){varuid=data.jwt;varuser=data.user;console.log("user",user);console.log("login successfull",uid);alert("login successfull",uid);window.location.href='/';}elseif(data.status==2){alert(data.msg);}}});}</script><body><br><br><divalign="center"><divid="qrcode"><imgsrc='iconLoading.gif'/></div><divid="profile"></div></div></body></html>
Enter fullscreen modeExit fullscreen mode

QRscanner:qrscanner2.blade.php
We scan and get the data from qr code and send the data

<!DOCTYPE HTML><html><head><scriptsrc="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script><scriptsrc="../frontend/qr/jquery.qrcode-0.11.0.min.js"></script></head><sectionclass="page-section"><divclass="container"><h2class="section-heading text-center">QR code scanner</h2><divclass="row setting-cards"><divclass="col-centered col-md-8"><ulclass="setting-card"><liclass="text-center"><?php $hashedid= HashUserID(Auth::user()->id); ?><p>passcode:<?php echo $hashedid; ?></p><p>Name:<?php echo Auth::user()->name;?></p><p>Email:<?php echo Auth::user()->email;?></p></li><liclass="text-center"><divid="qr-reader"class="col-md-8"></div><pid="login_mobile_scan_qrcode"></p><pid="qrcodedoLogin"></p></li></ul><divid="qr-reader-results"></div></div></div></div></section><sectionclass="page-section"></section></body><scriptsrc="../frontend/qr/html5-qrcode.min.js"></script><script>functionqrcodedoLogin(param){varurl=param;console.log("qrcodedoLogin called",url);$.ajax({type:"POST",dataType:"json",url:url,data:{//key:key},success:function(data){if(data.status==1){varqrcodeloginurl=data.msg;//scan successfull url recieved$('#qrcodedoLogin').text("QR Loggin successfully");// console.log("qrcodeloginurl",qrcodeloginurl);//qrcodedoLogin(qrcodeloginurl);}elseif(data.status==2){//couldn't do login// alert(data.msg);$('#qrcodedoLogin').text(data.msg);}}});}functionlogin_mobile_scan_qrcode(param){varurl=param;if("WebSocket"inwindow){varbase=window.location.hostname;varws=newWebSocket('wss://'+base+':8090');ws.onopen=function(){console.log("on WS open we sent the token to server");letparams=(newURL(url)).searchParams;leturltoken=params.get('t');ws.send(JSON.stringify({type:"client",step:0,token:urltoken}));};ws.onmessage=function(event){constdata=JSON.parse(event.data);console.log(" client body",data);conststep=data.data&&data.data.step;if(step===0){console.log("step",step);}elseif(step===1){ws.send(JSON.stringify({type:"client",step:1,username:'<?php echo $hashedid?>'}));}}ws.onclose=function(){console.log("Connection is closed...");};}else{alert("WebSocket NOT supported by your Browser!");}// console.log("login_mobile_scan_qrcode called",url);}functiondocReady(fn){// see if DOM is already availableif(document.readyState==="complete"||document.readyState==="interactive"){// call on next available ticksetTimeout(fn,1);}else{document.addEventListener("DOMContentLoaded",fn);}}docReady(function(){varresultContainer=document.getElementById('qr-reader-results');varlastResult,countResults=0;functiononScanSuccess(decodedText,decodedResult){if(decodedText!==lastResult){++countResults;lastResult=decodedText;// Handle on success condition with the decoded message.console.log(`Scan result${decodedText}`,decodedResult);resultContainer.innerHTML+=`<div>[${countResults}] -${decodedText}</div>`;login_mobile_scan_qrcode(decodedText);// Optional: To close the QR code scannign after the result is found// html5QrcodeScanner.clear();}}varhtml5QrcodeScanner=newHtml5QrcodeScanner("qr-reader",{fps:10,qrbox:250});html5QrcodeScanner.render(onScanSuccess);});</script>
Enter fullscreen modeExit fullscreen mode

Gist
Github of the projct

Top comments(6)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss
CollapseExpand
 
gimple profile image
gimple
gimple's the name, don't wear it out!
  • Location
    my house
  • Education
    clown college
  • Work
    semi-retired, focusing on my passion project
  • Joined

very cool!

CollapseExpand
 
sahilkashyap64 profile image
Sahil kashyap
I'm sahil kashyap
  • Location
    New Delhi
  • Work
    Full stack developer
  • Joined

thank you,I've added the github link,github.com/sahilkashyap64/qrlogin-...

CollapseExpand
 
naeemijaz profile image
Naeem Ijaz
Laravel Developer
  • Location
    Punjab, Pakistan
  • Education
    Bs in Computer Science
  • Joined

Sir it is working fine on local server
but when i upload it to the remote server it is giving me error

WebSocket {url: 'wss://qberg.mn/:8080', readyState: 0, bufferedAmount: 0, onopen: null, onerror: null, …}
qrtest:48 WebSocket connection to 'wss://qberg.mn/:8080' failed: Error during WebSocket handshake: Unexpected response code: 404
(anonymous) @ qrtest:48
dispatch @ jquery.min.js:2
v.handle @ jquery.min.js:2
qrtest:90 Connection is closed...

CollapseExpand
 
sahilkashyap64 profile image
Sahil kashyap
I'm sahil kashyap
  • Location
    New Delhi
  • Work
    Full stack developer
  • Joined

hi Naeem, Apologies for late reply. have you setup-ed the the wss properly on server.

  • The error message you shared says 404, maybe the url is wrong.
    • if it is not, Maybe try pinging the url using postman
CollapseExpand
 
alexvranich1 profile image
Alex vranich
  • Joined

How do I get the username that scanned the qr to be saved in a "Starts" table along with the time that person scanned the qr code

CollapseExpand
 
sahilkashyap64 profile image
Sahil kashyap
I'm sahil kashyap
  • Location
    New Delhi
  • Work
    Full stack developer
  • Joined

Get username who scanned the qr code
And make entry in Starts table?
If i'm understanding it wrong, kindly correct me.

here's the solution:

in this function

publicfunctionloginWS(Request$request)
Enter fullscreen modeExit fullscreen mode

I look for a

$key//$key is just hashed userID,i unhash it
Enter fullscreen modeExit fullscreen mode

And then I login

$user=Auth::loginUsingId($userid,true);// $user contains all the user details
Enter fullscreen modeExit fullscreen mode

/**
2 Ways to make entry in Starts table

  1. laravel provides ways to overRide login function,
  2. Simply add Starts Model in top and make an entry like this
useApp\Models\Starts;//place this query right after $user = Auth::loginUsingId($userid, true);$Starts=Starts::create(['userId'=>$userid,'somerandominfofromuser'=>$user->dummycolum,//asumming createdat or updatedat fields are autofilled and the model is properly setuped]);
Enter fullscreen modeExit fullscreen mode

*/

Unrelated to above here's a nice doc oflaravel not so popular tips

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

I'm sahil kashyap
  • Location
    New Delhi
  • Work
    Full stack developer
  • Joined

More fromSahil kashyap

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp