随着微信的普及,越来越多的网站开始支持微信扫描二维码登录的方式,大大降低了用户的使用注册成本,提高了用户体验。下面我们就来讲讲如何使用微信的扫一扫功能实现用户登录。
首先,我们必须有微信公众账号,并且拥有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,那么就会出发登陆。当然更加合理的方式是采用第二种主动推送的方式,我们将在下一篇博客中继续介绍。