随着微信的普及,越来越多的网站开始支持微信扫描二维码登录的方式,大大降低了用户的使用注册成本,提高了用户体验。下面我们就来讲讲如何使用微信的扫一扫功能实现用户登录。
首先,我们必须有微信公众账号,并且拥有oauth授权接口的权限,如果没有的话,还有个办法就是申请一个微信公众号的测试账号,完成开发功能后再切换到正式账号上使用。具体步骤参考微信公众平台及开发文档。我们这里着重讲解下YII2下的开发。整个登陆的流程如下所示:
第一步,用户访问网站登录页面,页面提供二维码。这里我们需要使用php生成二维码供用户使用,我们采用的是第三方的phpqrcode库来生成。在wechat控制器中增加auth-qr的action这样我们就可以通过wechat/auth-qr来获取二维码图片了。
public function actionAuthQr() { Yii::$app->response->format = Response::FORMAT_RAW; $code = HttpHelper::getParams('task_id', CommonHelper::guid()); Yii::$app->redis->setex('wechatLogin:'.$code, ((int)Yii::getAlias('@wechatQrTimer'))/60,$code); $url = Yii::getAlias('http://域名/wechat/auth-request/?task_id='.$code); QRcode::png($url,false, 'Q',4, 2); }
前台登陆页面的渲染如下:
<img id="qrimg" src="/wechat/auth-qr?task_id=<?= \common\helper\CommonHelper::guid()?>">
我们可以看到,每次访问我们会生成一个新的task_id存入redis里面,并且设置好过期时间。当用户使用手机扫描二维码时会自动跳转到二维码的内容url即/wechat/auth-request上,这里我们会向微信服务器发起认证。
public function actionAuthRequest() { $task_id = HttpHelper::getParams('task_id'); $r = Yii::$app->redis->get('wechatLogin:'.$task_id); if(isset($task_id) && isset($r)) { $callBack = '域名/wechat/auth-callback?'; $parms = 'task_id='.$task_id; $callBack .= $parms; $config = [ 'app_id' => '微信app_id', 'secret' => '微信app_secret', 'token' => '微信token', 'oauth' => [ 'scopes' => ['snsapi_base'], 'callback' => $callBack, ], ]; $app = new Application($config); $oauth = $app->oauth; $oauth->redirect()->send(); } else { return $this->render('/site/error',[ 'message' => '二维码已过期,请刷新登陆页面后重新扫描登陆. <a href="/site/signin">点击重新登陆</a>', 'name' => '二维码已过期', ]); } }
以上代码我们使用了第三方的微信开发库easywechat进行微信操作,具体的安装及使用请参考官方文档https://easywechat.org/zh-cn/docs/oauth.html
这样代码完成授权后回自动回调我们设置的callback网址,触发下面的代码
public function actionAuthCallback() { $config = [ 'app_id' => '微信app_id', 'secret' => '微信app_secret', 'token' => '微信token' ]; $app = new Application($config); $oauth = $app->oauth; $user = $oauth->user(); $task_id = HttpHelper::getParams('task_id'); Yii::$app->redis->set('wechatLogin:'.$code.':'.'.openid',$user->id); }
这样在完成授权后,回调url会自动获取用户id并写入redis缓存起来。
经过以上步骤用户的授权已经完成,接下来我们实现自动登陆的过程。一般来讲有两种方案,一种是采用前端ajax轮询的方式,每隔一段时间去query下服务器状态完成自动登陆,第二种是采用websocket主动推送的方式。本次我们就先简单的采用ajax轮询的方式实现登陆。
public function actionCheckWechatLogin() { $code = 0 ; $msg = ""; $task_id= HttpHelper::getParams('task_id'); $openid = Yii::$app->redis->get('wechatLogin:'.$task_id.'.openid'); if( $openid!= null) { $user = Admin::findOne(['wechat_id'=>$openid]); if($user != null && Yii::$app->user->login($user , 3600)) { $code= 1; $msg= "success"; Yii::$app->redis->del('wechatLogin:'.$task_id.'.openid'); } else { $code = 0 ; $msg = "登陆失败,微信未绑定或找不到微信对应用户,请刷新登陆页面后重新扫码登陆"; } } else { $code = 0 ; $msg = "openid不存在"; } Yii::$app->response->format=Response::FORMAT_JSON; return ['error_code'=>$code,'msg'=>$msg]; }
简单吧,这样前端只要写个ajax的timer一直不停请求后台,一旦回调函数写入redis了openid,那么就会出发登陆。当然更加合理的方式是采用第二种主动推送的方式,我们将在下一篇博客中继续介绍。