「实用」微信扫码 - 关注公众号后网站自动登录
??點擊上方?好好學java?,選擇?星標?公眾號
重磅資訊、干貨,第一時間送達 今日推薦:用好Java中的枚舉,真的沒有那么簡單!個人原創+1博客:點擊前往,查看更多 作者:destiny 鏈接:https://segmentfault.com/a/1190000022188562序言
常見方式
平常大家見到過最多的掃碼登錄應該是 開放平臺網頁登錄 大概形式就是:點擊微信登錄后會出現一個黑頁面,頁面中有一個二維碼,掃碼后可以自動獲取用戶信息然后登錄,但是這種方式需要申請開放平臺比較麻煩。如圖
「實用」微信掃碼關注公眾號號后自動登錄利于推廣方式
另外一種掃碼登錄方式只需要一個微信服務號就行,大概流程是:點擊微信登錄,網站自己彈出一個二維碼、掃描二維碼后彈出公眾號的關注界面、只要一關注公眾號網站自動登錄、第二次掃描登錄的時候網站直接登錄,大家可以體驗一下 「隨便找的一個網站」,這種掃碼登錄的方式個人覺得非常利于推廣公眾號
前期準備
服務號(或者微信測試賬號)
EasyWeChat 擴展包
梳理
其實第二種掃碼登錄的原理很簡單,核心就是依靠 微信帶參二維碼、EasyWeChat 二維碼文檔
簡單的解釋一下掃描這個帶參二維碼有什么不同:
掃描二維碼,如果用戶還未關注公眾號,則用戶可以關注公眾號,關注后微信會將帶場景值(自定義值)關注事件推送給開發者。
掃描二維碼,如果用戶已經關注公眾號,在用戶掃描后會自動進入會話,微信也會將帶場景值(自定義值)掃碼事件推送給開發者。
看到這里相信你已經明白了,梳理一下:
生成二維碼的時候你自定義一個參數到二維碼中,順便把這個參數傳到前端頁面中。
前端頁面根據這個參數輪詢用戶登錄狀態(也可使用 socket)。
用戶掃碼關注后會推送一個關注事件到服務端,也會把自定義參數帶入到事件中。
根據 openid 創建用戶后,然后在 Redis 中存儲 Key 為場景值(自定義參數) Value 為用戶創建后的 id。
前端輪詢方法中如果在 Redis 中獲取到 Id 后,Auth 登陸,頁面再重載一下,流程完畢。
實戰
請求登錄二維碼
前端通過一個點擊事件請求微信登錄二維碼
// 方便清除輪詢 let timer = null$(document).on('click', '.wechat-login', function () {// 請求登錄二維碼axios.get('{{ route('wx.pic') }}').then(response => {let result = response.dataif (result.status_code !== 200) {return}// 顯示二維碼圖片$('.wechat-url').attr('src', result.data.url)// 輪詢登錄狀態timer = setInterval(() => {// 請求參數是二維碼中的場景值axios.get('{{ route('home.login.check') }}', {params: {wechat_flag: result.data.weChatFlag}}).then(response => {let result = response.dataif (result.data) {window.location.href = '/'}})}, 2000)})})// 返回時清除輪詢$('.wechat-back').click(function () {clearInterval(timer)})后端生成帶參二維碼邏輯,EasyWeChat 配置請自行查閱 文檔
protected $app;/*** Construct** WeChatController constructor.*/public function __construct() {$this->app = app('wechat.official_account');}/*** 獲取二維碼圖片** @param Request $request** @return \Illuminate\Http\JsonResponse* @throws \Exception*/public function getWxPic(Request $request) {// 查詢 cookie,如果沒有就重新生成一次if (!$weChatFlag = $request->cookie(WxUser::WECHAT_FLAG)) {$weChatFlag = Uuid::uuid4()->getHex();}// 緩存微信帶參二維碼if (!$url = Cache::get(WxUser::QR_URL . $weChatFlag)) {// 有效期 1 天的二維碼$qrCode = $this->app->qrcode;$result = $qrCode->temporary($weChatFlag, 3600 * 24);$url = $qrCode->url($result['ticket']);Cache::put(WxUser::QR_URL . $weChatFlag, $url, now()->addDay());}// 自定義參數返回給前端,前端輪詢return $this->ajaxSuccess(compact('url', 'weChatFlag'))->cookie(WxUser::WECHAT_FLAG, $weChatFlag, 24 * 60);}用戶掃描二維碼后處理
/*** 微信消息接入(這里拆分函數處理)** @return \Symfony\Component\HttpFoundation\Response* @throws \EasyWeChat\Kernel\Exceptions\BadRequestException* @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException* @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException* @throws \ReflectionException*/public function serve() {$app = $this->app;$app->server->push(function ($message) {if ($message) {$method = camel_case('handle_' . $message['MsgType']);if (method_exists($this, $method)) {$this->openid = $message['FromUserName'];return call_user_func_array([$this, $method], [$message]);}Log::info('無此處理方法:' . $method);}});return $app->server->serve();}/*** 事件引導處理方法(事件有許多,拆分處理)** @param $event** @return mixed*/protected function handleEvent($event) {Log::info('事件參數:', [$event]);$method = camel_case('event_' . $event['Event']);Log::info('處理方法:' . $method);if (method_exists($this, $method)) {return call_user_func_array([$this, $method], [$event]);}Log::info('無此事件處理方法:' . $method);}/*** 取消訂閱** @param $event*/protected function eventUnsubscribe($event) {$wxUser = WxUser::whereOpenid($this->openid)->first();$wxUser->subscribe = 0;$wxUser->subscribe_time = null;$wxUser->save();}/*** 掃描帶參二維碼事件** @param $event*/public function eventSCAN($event) {if ($wxUser = WxUser::whereOpenid($this->openid)->first()) {// 標記前端可登陸$this->markTheLogin($event, $wxUser->uid);return;}}/*** 訂閱** @param $event** @throws \Throwable*/protected function eventSubscribe($event) {$openId = $this->openid;if ($wxUser = WxUser::whereOpenid($openId)->first()) {// 標記前端可登陸$this->markTheLogin($event, $wxUser->uid);return;}// 微信用戶信息$wxUser = $this->app->user->get($openId);// 注冊$nickname = $this->filterEmoji($wxUser['nickname']);$result = DB::transaction(function () use ($openId, $event, $nickname, $wxUser) {$uid = Uuid::uuid4()->getHex();$time = time();// 用戶$user = User::create(['uid' => $uid,'created_at' => $time,]);// 用戶信息$user->user_info()->create(['email' => $user->email,'nickname' => $nickname,'sex' => $wxUser['sex'],'address' => $wxUser['country'] . ' ' . $wxUser['province'] . ' ' . $wxUser['city'],'avatar' => $wxUser['headimgurl'],'code' => app(UserRegisterController::class)->inviteCode(10),'created_at' => $time,]);// 用戶賬戶$user->user_account()->create(['gold' => 200,'created_at' => $time,]);$wxUserModel = $user->wx_user()->create(['subscribe' => $wxUser['subscribe'],'subscribe_time' => $wxUser['subscribe_time'],'openid' => $wxUser['openid'],'created_at' => $time,]);Log::info('用戶注冊成功 openid:' . $openId);$this->markTheLogin($event, $wxUserModel->uid);});Log::debug('SQL 錯誤: ', [$result]);}/*** 標記可登錄** @param $event* @param $uid*/public function markTheLogin($event, $uid) {if (empty($event['EventKey'])) {return;}$eventKey = $event['EventKey'];// 關注事件的場景值會帶一個前綴需要去掉if ($event['Event'] == 'subscribe') {$eventKey = str_after($event['EventKey'], 'qrscene_');}Log::info('EventKey:' . $eventKey, [$event['EventKey']]);// 標記前端可登陸Cache::put(WxUser::LOGIN_WECHAT . $eventKey, $uid, now()->addMinute(30));}前端登錄檢查
/*** 微信用戶登錄檢查** @param Request $request** @return bool|\Illuminate\Http\JsonResponse*/public function loginCheck(Request $request) {// 判斷請求是否有微信登錄標識if (!$flag = $request->wechat_flag) {return $this->ajaxSuccess(false);}// 根據微信標識在緩存中獲取需要登錄用戶的 UID$uid = Cache::get(WxUser::LOGIN_WECHAT . $flag);$user = User::whereUid($uid)->first();if (empty($user)) {return $this->ajaxSuccess(false);}// 登錄用戶、并清空緩存auth('web')->login($user);Cache::forget(WxUser::LOGIN_WECHAT . $flag);Cache::forget(WxUser::QR_URL . $flag);return $this->ajaxSuccess(true);}OK,很實用的一個功能吧,趕快加到你項目中吧!
總結
以上是生活随笔為你收集整理的「实用」微信扫码 - 关注公众号后网站自动登录的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 一文介绍 Mysql 索引模型 B+ 树
- 下一篇: 一文读懂 volatile 关键字