How to realize PHP Swoole-based WeChat scan code login

With the popularity of WeChat, the scan code login method is increasingly used by current applications. It does not need to remember the password, as long as there is a WeChat account, you can log in conveniently and quickly. WeChat’s open platform natively supports scanning code login, but most people still use the public platform, so scanning code login can only be implemented by themselves. This is based on the temporary QR code with parameters of the WeChat public platform, and combined with Swoole's WebSocket service to achieve scan code login. The general process is as follows:

  1. The client opens the login interface and connects to the WebSocket service

  2. The WebScoket service generates a QR code with parameters and returns it to the client

  3. The user scans the QR code with parameters

  4. The WeChat server calls back the scan code event and notifies the developer server

  5. The developer server notifies the WebSocket service

  6. The WebSocket service notifies the client that the login is successful

Connect to WebSocket service

After installing Swoole, we need to use the 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) {
    
    

});

The message callback here is not practical, because all messages are sent by the server, but one must be set. If the set port number is lower than 1024, you must have root privileges. The server must remember to go to the firewall to open the port.

Generate QR code with parameters

After the WebSocket service is successfully connected to the client, a WeChat QR code with parameters needs to be generated and returned to the client to 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, so that the uniqueness of each client can be guaranteed. The effective time is set to 120 seconds to prevent a QR code from being scanned multiple times. When the message is pushed to the client, json is required to facilitate the client's processing. The client code is also very 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 scan code event

After displaying the QR code on the client, the user needs to be prompted to scan the code. For a user to scan a temporary QR code, WeChat will trigger a corresponding callback event, and we need to handle the user's scanning behavior in the callback event. Among them, we need to use some parameters passed by WeChat:

FromUserName    发送方帐号(一个OpenID)
MsgType         消息类型,event
Event           事件类型,subscribe
EventKey        事件 KEY 值,qrscene_为前缀,后面为二维码的参数值

Point to note here: micro letter has been concerned about the scan code push EventKeyis no qrscene_prefix, not only concerned about the scan code and then only concern.

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'){
    
      //关注
        return $this->subscribe($message);
    }
    if ($message['Event'] == 'unsubscribe') {
    
      //取消关注
        return $this->unsubscribe($message);
    }
    if ($message['Event'] == 'SCAN'){
    
       //已关注扫码
        return $this->scan($message);
    }
}else{
    
    
    return "您好!欢迎使用 SwooleWechat 扫描登录";
}

Here only explain the business logic of a concerned event, and the others should be coded as needed:

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,登录成功!\n这是你第%s次登录,玩的开心!";
    return sprintf($msgTemp, $user['nickname'], $count);
}

Here EventKeyis actually connected WebSocket client file descriptor, scan code to obtain the user OPEN_ID, according to a user OPEN_IDto obtain the user information, WebSocket service notification, response text message to a micro channel.

One of the more troublesome points here is how to notify the WebSocket service. We know that the code for processing WeChat callbacks is not on the WebSocket service, so how do different servers communicate? There are two solutions officially given by Swoole:

  1. An additional UDP port is monitored

  2. Use swoole_client as a client to access Server

Here we choose the second solution, Swoole 1.8 version supports one Server to monitor multiple ports, and we add a TCP port to monitor in the 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 main server is the WebSocket or Http protocol, the newly monitored TCP port will inherit the protocol settings of the main server by default, and the set method must be called separately to set the new protocol to enable the new protocol

Then we can notify the WebSocket service in the process of scanning the code 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);
}

Notify login success

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 client's browser to display the result. Remember the TCP port we just monitored? It can be processed 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);
});

The last login interface:

Made plans too much trouble, have to go to http://wechat.sunnyshift.com/index.phpthe test address to see.

Pay attention, don't get lost

Alright, everyone, the above is the entire content of this article. The people who can see here are all talents . As I said before, there are a lot of technical points in PHP, because there are too many, it is really impossible to write, and you will not read too much after writing it, so I will organize it into PDF and documents here, if necessary Can

Click to enter the secret code: PHP+「Platform」

Insert picture description here

Insert picture description here


For more learning content, please visit the [Comparative Standard Factory] excellent PHP architect tutorial catalog, as long as you can read it to ensure that the salary will rise a step (continuous update)

The above content hopes to help everyone . Many PHPers always encounter some problems and bottlenecks when they are advanced. There is no sense of direction when writing too much business code. I don’t know where to start to improve. I have compiled some information about this, including But not limited to: distributed architecture, high scalability, high performance, high concurrency, server performance tuning, TP6, laravel, YII2, Redis, Swoole, Swoft, Kafka, Mysql optimization, shell scripts, Docker, microservices, Nginx, etc. Many knowledge points, advanced advanced dry goods, can be shared with everyone for free, and those who need can join my PHP technology exchange group

Guess you like

Origin blog.csdn.net/weixin_49163826/article/details/109081303