Wechat code scanning login based on spool

Time:2021-6-22

With the popularity of wechat, code scanning login method is more and more used by current applications. Because it doesn’t need to remember the password, it can log in easily and quickly as long as there is a micro signal. Wechat’s open platform originally has the function of supporting code scanning login, but most people are still using the public platform, so code scanning login can only be realized by themselves. Based on the temporary QR code with parameters of wechat public platform, and combined with the websocket service of spool, we can realize the code scanning login. The general process is as follows:

  1. The client opens the login interface and connects to the websocket service
  2. The websocket service generates a two-dimensional code with parameters and returns it to the client
  3. QR code with parameters displayed by user scanning
  4. The wechat server calls back the code scanning event and notifies the developer server
  5. Developer server notifies websocket service
  6. Websocket service notifies the client of successful login

Connect to websocket service

After installing spool, we need to use websocket service. Creating a new websocket service is very simple

$server = new swoole_websocket_server("0.0.0.0", 1099);
$server->on('open', function (swoole_websocket_server $server, $request) use ($config){
    echo "server: handshake success with fd{$request->fd}\n";
});

$server->on('message', function (swoole_websocket_server $server, $frame) {

});

In fact, the message callback here is not used, because the server sends messages, but one must be set. If the set port number is less than 1024, you must have root permission. The server must remember to open the port in the firewall.

Generating two dimensional code with parameters

After the websocket service successfully connects to the client, it needs to generate a wechat QR code with parameters and return it to the client for display

$server->on('open', function (swoole_websocket_server $server, $request) use ($config){
    $app = Factory::officialAccount($config['wechat']);
    $result = $app->qrcode->temporary($request->fd, 120);
    $url = $app->qrcode->url($result['ticket']);
    $server->push($request->fd, json_encode([
        'message_type'    =>  'qrcode_url',
        'url'       =>  $url
    ]));
});

In the open callback, we generate a temporary QR code. The scene value of the QR code is the file descriptor of the client connection, which ensures the uniqueness of each client. The effective time is set to 120 seconds to prevent a QR code from being used by multiple code scans. Message push to the client must use JSON to facilitate client processing. The client code is also simple:

const socket = new WebSocket('ws://127.0.0.1:1099');
    socket.addEventListener('message', function (event) {
        var data = JSON.parse(event.data);
        if (data.message_type == 'qrcode_url'){
            $('#qrcode').attr('src', data.url);
        }
    });

Callback code scanning event

After displaying the QR code on the client, you need to prompt the user to scan the code. For users scanning temporary QR code, wechat will trigger the corresponding callback event, in which we need to deal with users’ code scanning behavior. We need to use some parameters from wechat:

Fromusername sender account (an openid)
Msgtype, message type, event
Event event type, subscribe
Eventkey event key value, qrscene_ Is the prefix, followed by the parameter value of the QR code

Here’s a point to note: wechat has paid attention to the importance of code scanning pushEventKeyNoqrscene_Prefix, only not pay attention to scan code and then pay attention to it.

After receiving the wechat callback, we first need to do different processing according to different event types:

if ($message['MsgType'] == 'event'){
    If ($message ['event '] ='subscribe') {// follow
        return $this->subscribe($message);
    }
    If ($message ['event '] = ='unsubscribe') {// unsubscribe
        return $this->unsubscribe($message);
    }
    If ($message ['event '] ='scan') {// code scanning followed
        return $this->scan($message);
    }
}else{
    Return "Hello! Welcome to swiolewechat scan login ";
}

Only one business logic that focuses on events will be explained here. Others will be coded according to their own needs

public function subscribe($message){
    $eventKey = intval(str_replace('qrscene_', '', $message['EventKey']));
    $openId = $message['FromUserName'];
    $user = $this->app->user->get($openId);
    $this->notify(json_encode([
        'type'  =>  'scan',
        'fd'    =>  $eventKey,
        'nickname'  =>  $user['nickname']
    ]));
    $count = $this->count($openId);
    $msgtemp =% s, login successful\ N this is your% s time to log in and have a good time! ";
    return sprintf($msgTemp, $user['nickname'], $count);
}

thereEventKeyIn fact, it is to connect the client file descriptor of websocket to obtain the user’s passwordOPEN_IDAccording to the user’sOPEN_IDGet user information, notify websocket service, and respond to text message to wechat.
A more troublesome point here is how to notify the websocket service. We know that the code for handling wechat callback is not on the websocket service, so how to communicate between different servers? There are two solutions officially provided by spool:

  1. Listen on an additional UDP port
  2. Using spool_ Client access server as client

Here we choose the second scheme. The version 1.8 of spool supports one server listening to multiple ports. We add a new TCP listening port in websocket service

$tcp_server = $server->addListener('0.0.0.0', 9999, SWOOLE_SOCK_TCP);
$tcp_server->set([]);
$tcp_server->on('receive', function ($serv, $fd, $threadId, $data) {
    
});

The primary server is websocket or HTTP protocol. The new monitored TCP port will inherit the protocol settings of the primary server by default. The new protocol can only be enabled by calling the set method to set the new protocol

Then we can notify the websocket service in the process of code scanning callback:

public function notify($message){
    $client = new swoole_client(SWOOLE_SOCK_TCP);
    if (!$client->connect('127.0.0.1', $this->config['notify_port'], -1)) {
        return "connect failed. Error: {$client->errCode}\n";
    }
    $ret = $client->send($message);
}

Notification login successful

After the websocket service receives the notification of successful login, it can process the user information as needed, and then pass the user information to the browser of the client to display the result. Do you remember the TCP port we just monitored? You can handle the following in the receive event:

$tcp_server->on('receive', function ($serv, $fd, $threadId, $data) {
    $data = json_decode($data, true);
    if ($data['type'] == 'scan'){
        $serv->push($data['fd'], json_encode([
            'message_type'    =>  'scan_success',
            'user'  =>  $data['nickname']
        ]));
    }
    $serv->close($fd);
});

Last login interface:
Wechat code scanning login based on spool

summary

The whole process is not difficult. The two main difficulties are the code scanning users corresponding to the connecting users and the communication between different servers. Our solution is to take the file descriptor of the connection as the temporary QR code scene value (redis can also be used to store the mapping relationship here), and listen to the new TCP port to receive the notification message. Accesshttp://wechat.sunnyshift.com/index.phpTry it. Remember to use the computer to open it.

The official account is sent back to the swoole-wechat to get the complete source code repository address.

Recommended Today

What is “hybrid cloud”?

In this paper, we define the concept of “hybrid cloud”, explain four different cloud deployment models of hybrid cloud, and deeply analyze the industrial trend of hybrid cloud through a series of data and charts. 01 introduction Hybrid cloud is a computing environment that integrates multiple platforms and data centers. Generally speaking, hybrid cloud is […]