优质文章,及时送达
链接:segmentfault.com/a/1192
序言
常见方式
平常大家见到过最多的扫码登录应该是 开放平台网页登录 大概形式就是:点击微信登录后会出现一个黑页面,页面中有一个二维码,扫码后可以自动获取用户信息然后登录,但是这种方式需要申请开放平台比较麻烦。如图
利于推广方式
另外一种扫码登录方式只需要一个微信服务号就行,大概流程是:点击微信登录,网站自己弹出一个二维码、扫描二维码后弹出公众号的关注界面、只要一关注公众号网站自动登录、第二次扫描登录的时候网站直接登录,大家可以体验一下 「随便找的一个网站」,这种扫码登录的方式个人觉得非常利于推广公众号。
此外公众号 Java后端,还发布过很多扫描登陆、扫描支付等实战交教程,关注公众号 Java后端 ,回复 666 即可下载。
前期准备
服务号(或者微信测试账号)
EasyWeChat 扩展包
梳理
其实第二种扫码登录的原理很简单,核心就是依靠 微信带参二维码、EasyWeChat 二维码文档
;id=mp1443433542&t=0.376179226179156
简单的解释一下扫描这个带参二维码有什么不同:
扫描二维码,如果用户还未关注公众号,则用户可以关注公众号,关注后微信会将带场景值(自定义值)关注事件推送给开发者。
看到这里相信你已经明白了,梳理一下:
登录微信公众号步骤如下:移动端:1、打开手机上的微信,点击右上角的放大镜图。2、在搜索框中输入“微信公众平台”,点击微信公众平台。3、点击进入公众号,点击“关注”,在对话框中输入“微信公众号登录”。4、点击链接进入。
生成二维码的时候你自定义一个参数到二维码中,顺便把这个参数传到前端页面中。
前端页面根据这个参数轮询用户登录状态(也可使用 socket)。
用户扫码关注后会推送一个关注事件到服务端,也会把自定义参数带入到事件中。
根据 openid 创建用户后,然后在 Redis 中存储 Key 为场景值(自定义参数) Value 为用户创建后的 id。
前端轮询方法中如果在 Redis 中获取到 Id 后,Auth 登陆,页面再重载一下,流程完毕。
实战
请求登录二维码
前端通过一个点击事件请求微信登录二维码
后端生成带参二维码逻辑,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)) {
登录微信公众号步骤如下:移动端:1、打开手机上的微信,点击右上角的放大镜图。2、在搜索框中输入“微信公众平台”,点击微信公众平台。3、点击进入公众号,点击“关注”,在对话框中输入“微信公众号登录”。4、点击链接进入。
$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"]);
申请成功就可以登陆,熟悉界面,功能还不能用,要等审核,审核通过很快,帮助文档里面说是7个工作日,事实上两三天就通过了。审核成功可以在右上角的邮件标志那看到。 问题八:手机怎么注册微信公众号 打开微信公众号网站,点击最右上角的“。
}
/ 自定义参数返回给前端,前端轮询
return $this->ajaxSuccess(compact('url','weChatFlag'))
登录微信公众号步骤如下:移动端:1、打开手机上的微信,点击右上角的放大镜图。2、在搜索框中输入“微信公众平台”,点击微信公众平台。3、点击进入公众号,点击“关注”,在对话框中输入“微信公众号登录”。4、点击链接进入。
}
用户扫描二维码后处理
*** 微信消息接入(这里拆分函数处理)** @return \Symfony\Component\HttpFoundation\Response* @throws \EasyWeChat\Kernel\Exceptions\BadRequestException* @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException* @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException* @throws \ReflectionException*public functionserve {$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 functionhandleEvent($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 functioneventUnsubscribe($event) {$wxUser = WxUser::whereOpenid($this->openid)->first;$wxUser->subscribe = 0;$wxUser->subscribe_time = ;$wxUser->save;}*** 扫描带参二维码事件** @param $event*public functioneventSCAN($event) {if ($wxUser = WxUser::whereOpenid($this->openid)->first) {/ 标记前端可登陆$this->markTheLogin($event,$wxUser->uid);return;}}*** 订阅** @param $event** @throws \Throwable*protected functioneventSubscribe($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(functionuse ($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 functionmarkTheLogin($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 functionloginCheck(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-
如果看到这里,说明你喜欢这篇文章,请 。同时 标星(置顶)本公众号可以第一时间接受到博文推送。
最近整理一份资料《Java技术栈学习手册》,覆盖了Java技术、面试题精选、Spring全家桶、Nginx、SSM、微服务、数据库、数据结构、架构等等。