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/, 歡迎各位大佬批評指正。

相關文章
相關標籤/搜索