С ростом популярности WeChat метод входа в систему со сканирующим кодом все чаще используется текущими приложениями. Поскольку не нужно запоминать пароль, если у вас есть учетная запись WeChat, вы можете войти в систему быстро и легко. Открытая платформа WeChat изначально поддерживает функцию входа в систему со сканирующим кодом, но большинство людей по-прежнему используют общедоступную платформу, поэтому вход в систему со сканирующим кодом могут реализовать только они сами. Это основано на временном QR-коде с параметрами на общедоступной платформе WeChat и в сочетании с сервисом Swoole WebSocket для входа в систему с кодом сканирования. Общий процесс выглядит следующим образом:
- Клиент открывает интерфейс входа и подключается к службе WebSocket.
- Сервис WebSocket генерирует QR-код с параметрами и возвращает его клиенту
- Пользователь сканирует отображаемый QR-код с параметрами
- Сервер WeChat вызывает событие кода сканирования и уведомляет сервер разработчика.
- Сервер разработчика уведомляет службу WebSocket
- Служба WebSocket уведомляет клиента об успешном входе в систему.
Подключиться к сервису WebSocket
После установки Swoole нам нужно использовать сервис WebSocket. Создать новый сервис WebSocket очень просто:
$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) {
});
Обратный вызов сообщения здесь не очень полезен, потому что сообщение отправляется сервером, но его нужно установить. Если установленный номер порта меньше 1024, у вас должны быть права root.Сервер не забывает обращаться к брандмауэру, чтобы открыть порт.
Сгенерировать QR-код с параметрами
После того, как служба WebSocket успешно подключилась к клиенту, ей необходимо сгенерировать QR-код WeChat с параметрами и вернуть его клиенту для отображения:
$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
]));
});
В открытом обратном вызове мы генерируем временный двумерный код. Значением сцены двумерного кода является дескриптор файла клиентского соединения, чтобы можно было гарантировать уникальность каждого клиента. Допустимое время установлено на 120 секунд, чтобы предотвратить использование одного QR-кода Zhang для нескольких сканирований. Когда сообщение отправляется клиенту, оно должно быть в формате json, что удобно для обработки клиентом. Код клиента также прост:
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);
}
});
Событие кода обратного вызова
После отображения QR-кода на клиенте пользователю необходимо отсканировать код. Чтобы пользователь мог отсканировать временный QR-код, WeChat инициирует соответствующее событие обратного вызова, и нам необходимо обработать поведение пользователя при сканировании кода в событии обратного вызова. Среди них нам нужно использовать некоторые параметры, переданные WeChat:
FromUserName 发送方帐号(一个OpenID)
MsgType 消息类型,event
Event 事件类型,subscribe
EventKey 事件 KEY 值,qrscene_为前缀,后面为二维码的参数值
Здесь следует отметить одну вещь: WeChat обратил внимание на отправку скан-кода.
EventKey
да нетqrscene_
префикс, только если вы не следуете коду сканирования, а затем следуете.
После получения обратного вызова WeChat нам сначала нужно выполнить различную обработку в соответствии с разными типами событий:
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 扫描登录";
}
Здесь объясняется только одна деловая логика, которая фокусируется на событиях, объясняется здесь, и другие кодируются по мере необходимости:
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);
}
здесьEventKey
На самом деле это файловый дескриптор клиента, который подключается к WebSocket и получает код сканирования пользователя.OPEN_ID
, по мнению пользователяOPEN_ID
Получите информацию о пользователе, уведомите службу WebSocket и ответьте текстовым сообщением в WeChat.
Один из наиболее проблемных моментов здесь — как уведомить службу WebSocket.Мы знаем, что код для обработки обратных вызовов WeChat не находится в службе WebSocket, так как же общаться между разными серверами? Swoole предлагает два официальных решения:
- Прослушивание дополнительного UDP-порта
- Используйте swoole_client в качестве клиента для доступа к серверу
Здесь мы выбираем второе решение. Версия Swoole 1.8 поддерживает сервер для прослушивания нескольких портов. Мы добавляем новый TCP-порт в службу WebSocket:
$tcp_server = $server->addListener('0.0.0.0', 9999, SWOOLE_SOCK_TCP);
$tcp_server->set([]);
$tcp_server->on('receive', function ($serv, $fd, $threadId, $data) {
});
Основной сервер — это протокол WebSocket или Http.Новый прослушиваемый TCP-порт наследует настройки протокола основного сервера по умолчанию, и новый протокол необходимо установить, вызвав метод set отдельно, чтобы включить новый протокол.
Затем мы можем уведомить службу WebSocket в процессе сканирования кода обратного вызова:
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);
}
Сообщить об успешном входе
После того, как служба WebSocket получит уведомление об успешном входе в систему, она может обработать информацию о пользователе по мере необходимости, а затем передать информацию о пользователе в браузер клиента для отображения результата.Помните новый TCP-порт, который мы только что прослушали? Это можно обработать в событии получения:
$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);
});
Последний интерфейс входа:
Суммировать
Весь процесс не сложен. Две основные трудности связаны со сканированием пользователя подключенного пользователя и связью между различными серверами. Наше решение — использовать дескриптор подключенного файла в качестве временного значения сцены QR-кода (это также можно использовать здесь). Redis для хранения отношения сопоставления), прослушивайте новый TCP-порт для получения уведомлений. может получить доступhttp://wechat.sunnyshift.com/index.php
Попробуйте, не забудьте открыть его на своем компьютере.
Отправьте «swoole-wechat» в фоновом режиме официального аккаунта, чтобы получить полный адрес склада исходного кода.