点击上方 Java后端,选择 设为星标

优质文章,及时送达


作者:destiny

链接:segmentfault.com/a/1190000022188562

序言

常见方式

平常大家见到过最多的扫码登录应该是 开放平台网页登录 大概形式就是:点击微信登录后会出现一个黑页面,页面中有一个二维码,扫码后可以自动获取用户信息然后登录,但是这种方式需要申请开放平台比较麻烦。如图

「实用」微信扫码关注公众号号后自动登录

利于推广方式

另外一种扫码登录方式只需要一个微信服务号就行,大概流程是:点击微信登录,网站自己弹出一个二维码、扫描二维码后弹出公众号的关注界面、只要一关注公众号网站自动登录、第二次扫描登录的时候网站直接登录,大家可以体验一下 「随便找的一个网站」,这种扫码登录的方式个人觉得非常利于推广公众号。

此外公众号 Java后端,还发布过很多扫描登陆、扫描支付等实战交教程,关注公众号 Java后端 ,回复 666 即可下载。

前期准备

  • 服务号(或者微信测试账号)

  • EasyWeChat 扩展包

梳理

其实第二种扫码登录的原理很简单,核心就是依靠 微信带参二维码、EasyWeChat 二维码文档

https://mp.weixin.qq.com/wiki?action=doc&id=mp1443433542&t=0.376179226179156

https://www.easywechat.com/docs/4.0/basic-services/qrcode

简单的解释一下扫描这个带参二维码有什么不同:

  • 扫描二维码,如果用户还未关注公众号,则用户可以关注公众号,关注后微信会将带场景值(自定义值)关注事件推送给开发者。

  • 扫描二维码,如果用户已经关注公众号,在用户扫描后会自动进入会话,微信也会将带场景值(自定义值)扫码事件推送给开发者。

看到这里相信你已经明白了,梳理一下:

  • 生成二维码的时候你自定义一个参数到二维码中,顺便把这个参数传到前端页面中。

  • 前端页面根据这个参数轮询用户登录状态(也可使用 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,很实用的一个功能吧,赶快加到你项目中吧!


-END-

如果看到这里,说明你喜欢这篇文章,请 转发、点赞。同时 标星(置顶)本公众号可以第一时间接受到博文推送。

1. 2020 年 5 月全国程序员工资出炉!

2. 使用 Docker 部署 Spring Cloud 项目详细步骤

3. 一行命令下载全网视频

4. 彻底理解 SpringIOC、DI

最近整理一份资料《Java技术栈学习手册》,覆盖了Java技术、面试题精选、Spring全家桶、Nginx、SSM、微服务、数据库、数据结构、架构等等。

获取方式:点“ 在看,关注公众号 Java后端 并回复 777 领取,更多内容陆续奉上。

喜欢文章,点个在看 

微信扫码:关注公众号后网站自动登录的实现原理相关推荐

  1. 「实用」微信扫码 - 关注公众号后网站自动登录

    点击上方 好好学java ,选择 星标 公众号 重磅资讯.干货,第一时间送达 今日推荐:用好Java中的枚举,真的没有那么简单!个人原创+1博客:点击前往,查看更多 作者:destiny 链接:htt ...

  2. 微信扫码 - 关注公众号后网站自动注册并登录的实现

    微信扫码 - 关注公众号后网站自动注册并登录的实现 需求描述 在自己网站上点击微信登录,网站自己弹出一个二维码.扫描二维码后弹出公众号的关注界面.只要一关注公众号网站自动登录.第二次扫描登录的时候网站 ...

  3. 实现微信扫码或关注公众号后网站自动登录

    常见方式 平常大家见到过最多的扫码登录应该是 开放平台网页登录 大概形式就是:点击微信登录后会出现一个黑页面,页面中有一个二维码,扫码后可以自动获取用户信息然后登录,但是这种方式需要申请开放平台比较麻 ...

  4. PHP微信扫码关注公众号并授权登录源码

    PHP微信扫码登录看起来简单,但做起来有点麻烦,开发起来就会浪费很多的时间. PHP判断是否首次关注公众号,扫码关注公众号获取微信用户头像.openid和省市等信息源码. 演示体验地址: https: ...

  5. 最新PHP微信扫码关注公众号并授权登录源码

    正文: PHP微信扫码登录看起来简单,但做起来有点麻烦,开发起来就会浪费很多的时间. PHP判断是否首次关注公众号,扫码关注公众号获取微信用户头像.openid和省市等信息源码. 第一步:获取关注二维 ...

  6. php关注公众号代码,PHP微信扫码关注公众号源码

    附上数据库信息:CREATE TABLE IF NOT EXISTS `qrcode` ( `id` int(11) unsigned NOT NULL, `addtime` int(10) NOT  ...

  7. WECHAT 微信扫码关注公众号方法无法获取头像和昵称了

    请注意: 20年6月8日起,用户关注来源"微信广告(ADD_SCENE_WECHAT_ADVERTISEMENT)"从"其他(ADD_SCENE_OTHERS)" ...

  8. PHP微信扫码关注公众号并登录

    2019独角兽企业重金招聘Python工程师标准>>> https://www.sucaihuo.com/php/1414.html 转载于:https://my.oschina.n ...

  9. 扫码关注公众号登录系统

    微信开发--扫码关注公众号登录系统 前言 准备阶段 NATAPP 测试账号 工具代码 微信 API 调研阶段 步骤1:注册账号(如果使用测试账号可跳过) 步骤2:了解微信扫码机制 步骤3:了解微信消息 ...

最新文章

  1. 在应用程序中宿主MEF
  2. Eclipse常用功能键
  3. 创建emp表 oracle,Oracle中创建和管理表详解
  4. 微软正式释出基于 Chromium 的 Edge 预览版本
  5. 实现一个用户取过的数据不被其他用户取到
  6. 用css3制作一个搜索框效果
  7. 【Objective-C】类与结构体的区别
  8. Python+OpenCV:阈值分割
  9. cdt规约报文用程序解析_程序员必备的学习笔记《TCP/IP详解(二)》
  10. hadoop常见问题汇总
  11. C语言 数组和指针
  12. 数据终端设备与无线通信模块之间串行通信链路复用协议(TS27.010)在嵌入式系统上的开发【转】...
  13. 世界史上的6大古帝国
  14. ORID方法在敏捷中的利用
  15. C语言 找数字,用(折半查找法或二分查找法)
  16. 使用Python绘制热图的库 pyHeatMap 使用Python绘制热图的库 pyHeatMap
  17. 【课程·研】软件工程 | 结对编程:建造金字塔(1157)
  18. 关于JS下offsetLeft,style.left,以及jquery中的offset().left,css(left)的区别。
  19. android中gravity什么意思,浅谈android 中layout_gravity和gravity
  20. #ifndef的神仙用法

热门文章

  1. 数学建模学习笔记(13)分类模型
  2. Minimum Barrier Salient Object Detection at 80 FPS 论文阅读笔记
  3. 2017海尔顺逛发展战略发布:诚信平台引爆社群经济
  4. 软考中级-软件设计师-第2章 计算机组成与体系结构
  5. React 组件设计指南
  6. CentOS 7.6 部署squid代理服务器
  7. 最新.net面试题及答案
  8. JavaSwing3
  9. 牛客网(Java)——三角形
  10. 检测导航仪GPS端口的工具