掃碼登陸成爲一種日趨流行的登陸方式,它具備較高的安全性,同時又使咱們從記憶大量的帳號密碼並手動輸入的繁瑣流程中解脫出來,有些平臺甚至無帳號也能掃碼登陸,連註冊的麻煩都省了。php
對於接入微信開放平臺的公衆號應用來講,實現掃碼登陸是至關容易的,有 EasyWeChat SDK 加持,再按着官方的文檔一把梭,很快就能完成。 然而本文所要討論的是另外一種狀況,有時候出於某些緣由,本身的公衆號不能接入開放平臺,但又想進行微信掃碼登陸,這種狀況下顯示就不能再換官方的套路來了。但只要咱們稍做變通,就能實現這一需求。html
如下就來介紹一下具體實現,先放效果圖。前端
配合本文,我建立了一個簡單的示例項目,有興趣的能夠克隆下來,配合源碼一塊兒服用,效果更佳。項目地址:github.com/tianyong90/…mysql
laravel-echo
和 socket.io-client
前端監聽事件廣播是關鍵,咱們須要一個 websocket 服務端,Laravel 官方文檔在介紹消息廣播時提到了 Pusher 和 laravel-echo-server。由於我使用 laradock 做爲開發環境,其中內置了 laravel-echo-server 容器,十分方便,因此決定直接用它。實際上也可使用 Pusher 服務,那麼則須要安裝 pusher.js 替代 socket.io-client,同時在 .env 中修改相關配置nginx
主要是配置數據庫和 redis 鏈接,而後把 BROADCAST_DRIVER 設置爲 redis(這一點很重要,若是使用 pusher 則須要修改成 pusher)laravel
若是 QUEUE_CONNECTION 設置爲 redis 了,則須要記得啓動隊列 worker.git
由於使用 laradock,因此只須要啓動時帶上 laravel-echo-server 參數就能夠了,進入 laradock 目錄github
docker-compose up -d nginx php-worker nginx mysql redis laravel-echo-server
複製代碼
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
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();
}
複製代碼
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 }} />>
複製代碼
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/, 歡迎各位大佬批評指正。