Laravel + Laravel-echo + EasyWeChat 实现微信扫码登陆

扫码登陆成为一种日趋流行的登陆方式,它具备较高的安全性,同时又使咱们从记忆大量的帐号密码并手动输入的繁琐流程中解脱出来,有些平台甚至无帐号也能扫码登陆,连注册的麻烦都省了。php

对于接入微信开放平台的公众号应用来讲,实现扫码登陆是至关容易的,有 EasyWeChat SDK 加持,再按着官方的文档一把梭,很快就能完成。 然而本文所要讨论的是另外一种状况,有时候出于某些缘由,本身的公众号不能接入开放平台,但又想进行微信扫码登陆,这种状况下显示就不能再换官方的套路来了。但只要咱们稍做变通,就能实现这一需求。html

基本思路:

  1. 登陆页显示微信二维码(使用 EasyWeChat SDK 建立,短时效的临时二维码)
  2. 用户扫码后推送消息到服务器接口,接口中根据业务状况进行判断处理,符合条件时触发 WechatScanLogin 事件
  3. WechatScanLogin 事件实现 ShouldBroadcast 接口,因此当它被触发时也会向指定的频道进行广播
  4. 前端 laravel-echo 监听频道中用户扫码登陆的消息并进行处理

如下就来介绍一下具体实现,先放效果图。前端

screenshot

具体实现

配合本文,我建立了一个简单的示例项目,有兴趣的能够克隆下来,配合源码一块儿服用,效果更佳。项目地址:github.com/tianyong90/…mysql

  1. 首先固然是建立 Laravel 项目,同时安装先后端依赖
  • 前端最主要依赖是 laravel-echosocket.io-client

前端监听事件广播是关键,咱们须要一个 websocket 服务端,Laravel 官方文档在介绍消息广播时提到了 Pusher 和 laravel-echo-server。由于我使用 laradock 做为开发环境,其中内置了 laravel-echo-server 容器,十分方便,因此决定直接用它。实际上也可使用 Pusher 服务,那么则须要安装 pusher.js 替代 socket.io-client,同时在 .env 中修改相关配置nginx

  1. 配置项目

主要是配置数据库和 redis 链接,而后把 BROADCAST_DRIVER 设置为 redis(这一点很重要,若是使用 pusher 则须要修改成 pusher)laravel

若是 QUEUE_CONNECTION 设置为 redis 了,则须要记得启动队列 worker.git

  1. 启动 laravel-echo-server

由于使用 laradock,因此只须要启动时带上 laravel-echo-server 参数就能够了,进入 laradock 目录github

docker-compose up -d nginx php-worker nginx mysql redis laravel-echo-server
复制代码
  1. 建立 WechatScanLogin 事件
php artisan make:event WechatScanLogin
复制代码
class WechatScanLogin implements ShouldBroadcast {
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public $token;

    /** * Create a new event instance. * * @param $token */
    public function __construct($token) {
        $this->token = $token;
    }

    /** * Get the channels the event should broadcast on. * * @return \Illuminate\Broadcasting\Channel|array */
    public function broadcastOn() {
        return new Channel(‘scan-login’);
    }
}
复制代码

上面最关键的就是事件要实现 ShouldBroadcast 接口并在 broadcastOn 方法中指定要广播的频道。WechatScanLogin 的公开属性 token 会自动包含在广播数据中。web

  1. 对接微信消息服务器

laravel-wechat 的相关配置和对接,请阅读 EasyWeChat SDK 官方文档。redis

接收扫码的消息并进行相关处理。

public function serve() {
    $app = app('wechat.official_account');

    $app->server->push(function ($message) {
        if ($message['Event'] === 'SCAN') {
            $openid = $message['FromUserName'];

            $user = User::where('openid', $openid)->first();

            if ($user) {
                // TODO: 这里根据状况加入其它鉴权逻辑

                // 使用 laravel-passport 的我的访问令牌
                $token = $user->createToken($user->name)->accessToken;

                // 广播扫码登陆的消息,以便前端处理
                event(new WechatScanLogin($token));

                \Log::info('haha login');
                return '登陆成功!';
            }

            return '失败鸟';
        } else {
            // TODO: 用户不存在时,能够直接回返登陆失败,也能够建立新的用户并登陆该用户再返回
            return '登陆失败';
        }
    }, \EasyWeChat\Kernel\Messages\Message::EVENT);

    return $app->server->serve();
}
复制代码
  1. 使用 EasyWeChat 建立临时二维码并在页面中显示。
public function index() {
    $wechat = app('wechat.official_account');

    $result = $wechat->qrcode->temporary('foo', 600);
    $qrcodeUrl = $wechat->qrcode->url($result['ticket']);

    return view('index', compact('qrcodeUrl'));
}
复制代码
<img src={{ qrcodeUrl }} />>
复制代码
  1. 前端使用 laravel-echo 订阅对应的微信扫码登陆事件,接收其中的 token 并存入本地存储做为判断是否登陆的凭据,同时这个 token 也将做为访问后端 api 的受权依据。注意前面的代码中,使用了 laravel-passport 生成这个我的访问令牌,若是不了解这部分原理,请查阅 Laravel 官方文档。
import Echo from 'laravel-echo'
import io from 'socket.io-client'

window.io = io

let EchoInstance = new Echo({
  broadcaster: 'socket.io',
  host: window.location.hostname + ':6001',
})

EchoInstance.channel('scan-login').listen('WechatScanLogin', e => {
    localStorage.setItem('my_token', this.token)

    // 其它处理
  })
复制代码

总结

至此,简单的扫码登陆就完成了。固然,本文示例代码不怎么优雅、流程可能也有不完善的地方,主要是为了提供一个大体思路。有了这个思路,咱们能够实现其它诸如扫码签到、扫码投票等各类功能,具体如何就看你们的创意了。

最后放上我的博客地址:tianyong90.com/, 欢迎各位大佬批评指正。

相关文章
相关标签/搜索