实现PC端微信扫码登录,无需关注微信公众号
文章目录
PC端微信扫码登录,无需关注微信公众号即可登录.无需开放平台,无需甚至不需要掏每年审核费用..
常见方案有两种
1,微信开发者平台(http://open.weixin.qq.com) 的网页oauth方案. 好像需要300一年,这种方案是免关注,此方法能返回微信用户基本信息
2,微信本身有生成二维码功能,但是要想要实现扫码登陆,其实就消息机制(也就是必须关注才能),此方法也能返回微信用户基本信息.
为啥不用现成的
我自己不是用的这两种方法.因为我自己用了一个微信自动回复的addons ,它已经占用了接口配置URL , 我要使用微信扫码登录,只能修改它代码.
我还有另外一个情况就是,我的微信公众号是测试账号(申请地址) ,只能关注100个人.
自己方案
1, 用户pc访问 login.html登陆页面
2, login.html 已经登陆的情况下,和普通登陆情况一致,直接跳转后台或者用户页面.
3, 如果未登录,那么生成 request_str 随机字符串. 并写入数据库,将字符串加入session.
3.1 此页面视图文件只是显示一个二维码 (qr.php),二维码的内容是一个网址, /wx_login.php?request_str=$request_str ;
3.2 同时pc页面login.html 轮询ajax请求 判断手机用户是否扫码成功,扫码成功就写入数据库,然后自动登录
4, 用户通过扫码访问带参数的二维码(也就是访问了wx_login.php?request_str=$request_str )
4.1 将参数中request_str加入session['wx_request_str'] ,最后回调页面需要用.
4.2 微信上自动跳转到微信oauth登陆页面.
5, 手机上oauth微信授权登陆成功跳转到回调页面login_callback,读取session['wx_request_str'],并将用户openid写入数据库
5.1 此时PC端AJAX请求判断扫码成功,登陆处理
--- 此时 3.2 步在反复轮询,读取数据库中的到 openid 知道用户已经登陆.
6,完成登录.
一切基于thinkphp5
use EasyWeChat\Foundation\Application; //EasyWeChat 3.x 微信套件
use addons\wechat\library\Config as ConfigService; //读取微信公众号的基本配置
use \think\Request; //thinkphp 获得参数 头信息
use \think\Session; //thinkphp session 管理
use Endroid\QrCode\QrCode; //二维码生成
use app\admin\library\Auth; //fastadmin 登录类
use app\admin\model\Admin; //fastadmin 管理员模型
初始化部分
protected $logined = false; //登录状态
protected $login_url =''; //后台登陆页面
protected $tips_url =''; //手机页面报错或者成功提示
protected $config =[];
public $app = null;
public function _initialize()
{
parent::_initialize();
//手机扫码回调地址
$call_url = Request::instance()->domain().url('/addons/wxlogin/index/login_callback',['t'=>time()]);
//PC授权后登录的页面
$this->login_url = Request::instance()->domain().url('/admin/index/index'); //(可以用url('','','',true) 直接生成带域名)
//手机扫码成功/或者失败跳转的页面
$this->tips_url = Request::instance()->domain().url('/addons/yakeblog/index');
//读取微信appid之类的.
$this->config = ConfigService::load();
//修改授权方式 (因为我是测试公众号相当于认证的服务号,有snsapi_base权限)
$this->config['oauth']['scopes'][0] = 'snsapi_base'; //snsapi_base微信认证服务号;认证订阅号snsapi_userinfo
//修改授权为回调地址
$this->config['oauth']['callback'] = $call_url;
//dump($config);exit;
//初始化 EasyWeChat
$this->app = new Application($this->config);
}
PC登录页面login控制器
public function login()
{
$auth = Auth::instance();
//判断是否登陆,如果登陆了直接跳转后台
if($auth->isLogin()){
$this->redirect($this->login_url);
exit;
}
//当前时间
$time = time();
//读取请求字符串session ,防止反复请求.
$request_str = Session::get('request_str');
//如果请求字符串存在就验证数据库
if(!empty($request_str)){
$info = db('wxlogin')->where('request_str',$request_str)->find();
//如果数据库存在,判断是否过期,是否已经扫码
if(!empty($info) && ( $info['overtime'] >= $time ) && empty($info['openid']) ) {
$request_str = $info['request_str'];
$overtime = $info['overtime'];
}else{
$request_str = ''; //设置为空,后面处理
}
}
//如果不存在或者过期,那么重新生成
if(empty($request_str)){
$request_str = $this->random(). $time ; //生成随机字符串,后面追加时间,防止相同
Session::set('request_str',$request_str); //写入session
$overtime = $time +60 ; //60秒有效期
//写入数据库
db('wxlogin')-> insert(['request_str'=>$request_str,'overtime'=>$overtime]);
}
$this->assign('overtime',$overtime); //传入有效期
return $this->view->fetch('login');
}
此页面控制器业务逻辑相当简单,生成随机字符串,$this->random() (是一个随机生产字符串的函数,这里不提供了,php7.0自带,我的是5.5另外找的)
判断有没有过期,没过期,没被使用就继续用.有用过就重新生成.并写入数据库,同时加入session
login对应的视图文件
此页面也相当简单就显示一个二维码 示例页面( https://login.getce.cn) <本站已经改成小程序扫描登陆>
js代码部分就是反复ajax请求 /addons/wxlogin/index/is_login,判断是否登录.
res.code 有三种情况:
-1 :错误
0 :等待用户登录信息
1:成功.
可以自己扩展
手机页面控制器
//判断是否微信浏览器
public function is_weixin(){
if ( strpos($_SERVER['HTTP_USER_AGENT'], 'MicroMessenger') !== false ) {
return true;
}
return false;
}
//手机端登陆接口
//此页面是电脑生成带参数二维码,手机扫码访问的入口
public function wx_login()
{
if($this->is_weixin()){
$time = time();
//获取参数
$request_str = $this->request->param('request_str/s');
if(!empty($request_str)){
Session::set('wx_request_str',$request_str); //写入session,加个微信wx前缀,用于回调链接使用
//读取数据库中 access_token,access_token每日调用次数有限,防止重复请求
$info = db('wxlogin_token')->where('app_id',$this->config['app_id'])->find();
$accessToken = $this->app->access_token;
//如果还在有效期
if (!empty($info) && !empty ($info['access_token']) && ($info['overtime'] >= $time) ){
$this->app['access_token']->setToken($info['access_token']);
}else{
//如果已经过期
$token = $accessToken->getToken(true); // 强制重新从微信服务器获取 token.
if (!empty($token)){
//更新或者新增记录
if(empty($info)){
db('wxlogin_token')-> insert(['app_id'=>$this->config['app_id'],'access_token'=>$token,'overtime'=> $time+3600]);
}else{
db('wxlogin_token')
->where('app_id',$this->config['app_id'])
->update(['access_token'=>$token, 'overtime'=> $time+3600]);
}
}else{
$this->error('请求access_token错误',$this->tips_url);
}
}
$oauth = $this->app->oauth;
// 未登录
if (empty($_SESSION['wechat_user'])) {
return $oauth->redirect();
}
}else{
$this->error('扫码参数错误!',$this->tips_url);
}
}else{
$this->error('请微信中访问!');
}
}
//手机页面.登陆回调页面,处理用户授权后登录逻辑
public function login_callback()
{
$user = $this->app->oauth->user();
$time = time();
//获取授权参数
$request_str = Session::get('wx_request_str');
Session::set('wx_request_str',NULL); //清理session
if(!empty($request_str)){
$info = db('wxlogin')->where('request_str',$request_str)->find();
//数据库存在,且未到有效期,并且没有写入openid的情况.
if(!empty($info) && ( $info['overtime'] >= $time ) && empty($info['openid']) ){
db('wxlogin')->where('id',$info['id'])->update(['openid'=>$user->id,'oktime'=>$time]);
$this->success('授权成功,现在PC端已经登陆!',$this->tips_url);
}else{
$this->error('可能已经授权',$this->tips_url);
}
}else{
$this->error('参数错误',$this->tips_url);
}
}
可以无需视图文件,我没视图文件,只有控制器
手机上就两个页面,当然你也可以自己扩展,
1,wx_login.php?request_str = xxxxxxxxxxxxx
参数是PC端生成的URL二维码传过来的.
读取数据库看有没有过期,又没被使用过这个参数.
没有使用,没过期就授权登录,当然需要将request_str参数加入session
$oauth = $this->app->oauth;
return $oauth->redirect();
2, 授权成功回调页面 login_callback.php
读微信oauth的用户openid
然后将openid写入wxlogin表,表示已经登陆.
那么手机上就完成了全部业务