如何用微信公众号二维码事件做扫码登陆

实现功能:

将微信二维码事件用作微信扫码登陆!!!

背景思路:
1、微信公众号获取用户信息需要微信浏览器打开才能获取
2、pc端使用微信登陆,需要微信开发者这个,认证需要每年300,实际上只有扫码登陆功能是有用的
3、微信二维码事件,可以根据二维码的信息,用户扫码之后可以根据二维码记录的信息处理业务需求
4、使用微信公众号的二维码做PC端的扫码登陆,理论上是没问题的

思路一:
1、生成用户登陆二维码
2、用户扫码之后记录session
3、前端启用定时器,后台检测有session,返回跳转链接到前台,前台跳转
开发的时候发现,用户扫码之后,记录了session,登陆控制器并不能获取到这个session,what the fuck!
手机端保存的session 怎么可能在pc端使用呢?当时是不是傻了!

居然如此那就创建一张数据表来记录吧!

创建扫码登陆记录表 login

CREATE TABLE `login` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `openid` varchar(45) DEFAULT NULL,
  `uid` int(11) DEFAULT NULL COMMENT '用户id',
  `code` varchar(32) DEFAULT NULL COMMENT '唯一code',
  `create_time` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `code` (`code`) USING BTREE
) ENGINE=MyISAM AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;

前端HTML


<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <link rel="icon" href="__HOME__/img/favicon.ico"/>
    <title>微信登录title>
    <style>
        .impowerBox{
            display:inline-block;vertical-align:middle
        }
        p{margin:0;font-weight:400}
        img{border:0}
        body{font-family:"Microsoft Yahei";color:#fff;background:0 0}
        .impowerBox{line-height:1.6;position:relative;width:100%;z-index:1;text-align:center}
        .impowerBox .title{text-align:center;font-size:20px}
        .impowerBox .qrcode{width:280px;margin-top:15px;border:1px solid #E2E2E2}
        .impowerBox .info{width:280px;margin:0 auto}
        .impowerBox .status{padding:7px 14px;text-align:left}
        .impowerBox .status.normal{margin-top:15px;background-color:#232323;border-radius:100px;-moz-border-radius:100px;-webkit-border-radius:100px;box-shadow:inset 0 5px 10px -5px #191919,0 1px 0 0 #444;-moz-box-shadow:inset 0 5px 10px -5px #191919,0 1px 0 0 #444;-webkit-box-shadow:inset 0 5px 10px -5px #191919,0 1px 0 0 #444}
        .impowerBox .status.status_browser{text-align:center}
        .impowerBox .status p{font-size:13px}
    style>
head>
<body style="background-color: rgb(51, 51, 51); padding: 50px;">
<div class="impowerBox">
    <div class="title">微信登录div>
    <img class="qrcode" src="{$login.img}" id="wxewm">
    <input type="hidden" name="code" value="{$login.code}">
    <div class="info">
        <div class="status status_browser normal">
            <p>1、请使用微信扫描二维码登录p>
            <p>2、关注“五五科技”公众号p>
        div>
    div>
div>
<script src="//cdn.bootcss.com/jquery/1.12.1/jquery.min.js">script>
<script type="text/javascript">

    var t1 ='';
    $(function() {
        //定时查询验证登录
        t1 = window.setInterval("login()",2000);
        setTimeout("end()",300000);
    });
    function end(){  //停止定时器
        $('#wxewm').hide();   //隐藏二维码
        clearInterval(t1);    //清除定时器
        $('.status_browser').html('

二维码已经过期,请刷新页面

'
); } // window 失去焦点,停止输出 window.onblur = function() { clearInterval(t1); }; // window 每次获得焦点 window.onfocus = function() { t1 = window.setInterval("login()",2000); }; function login(){ //验证是否扫描二维码 var code =$('input[name=code]').val(); var url = "{:U('Home/Login/checkLogin')}"; $.post(url,{code:code},function(data){ if(data.status){ window.location.href=data.url; } }); }
script> body> html>

login控制器

#微信扫码登录
public function login(){
    $code = "LOGIN_".substr(strtoupper(md5(date('Y-m-d H:i:s', time()) . mt_rand())), -16);
    $img = $this->getqcode($code);
    $data['code'] = $code;
    $data['img'] = $img;
    $this->assign('login',$data);
    $this->display();
}
#获取二维码
public function getqcode($code){
    $errmsg = $this->WechatAuth->qrcodeCreate('QR_STR_SCENE',$code,300);
    if($errmsg['errcode']==0){
        $img = 'https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket='.$errmsg['ticket'];
        return $img;
    }else{
        return false;
    }
}
public function checkLogin(){
    $code = trim(I('post.code'));
    if(empty($code)){
        $this->ajaxReturn(array('status'=>0,'msg'=>'code不存在'));
    }

    $uid = M('login')->where(['code'=>$code])->getField('uid');
    $url = $this->backUrl();
    if(!$url){
        $url = C('DOMAIN').U('Home/Company/index');
    }
    if($uid){
     //将code置为null 方便下次扫码
        M('login')->where(['uid'=>$uid])->setField('code',null);
        $user_info = M('user')->find($uid);
        if($user_info){
            session('user_info', $user_info);
            session('user_uid',$user_info['id']);
            $this->ajaxReturn(array('status'=>1,'msg'=>'登录成功,马上为您跳转..^_^','url'=>$url));
        }
    }
    $this->ajaxReturn(array('status'=>0,'msg'=>'无登录信息'));
}

微信控制器

/**
     * 微信入口
     */
    public function index(){
        $this->wechat->valid();//明文或兼容模式可以在接口验证通过后注释此句,但加密模式一定不能注释,否则会验证失败
        $wx_data = $this->wechat->getRev()->getRevData();   //获取微信数据
        $openid = $wx_data['FromUserName'];
        $wx_userinfo = $this->getUserByopenid($openid);
        if(!$wx_userinfo){
            $wx_userinfo = $this->wechat->getUserInfo($openid);
            if(!$wx_userinfo){
                Log::write('miss userInfo', 'ERR', '', C('LOG_DATA_PATH') . 'weixin/error/' .date('Ym') .'/'. date('md') . '.log');
                $this->WechatAuth->sendText(C('WX_JINGZHI'),"获取用户信息失败!");
                M('access_token')->delete();
            }
            if($wx_userinfo){
                //添加用户
                $user_id = $this->addUser($wx_userinfo);
                exit;
            }
        }
        if(!$wx_userinfo){
            exit;
        }
        $type = $wx_data['MsgType'];    //消息类型
        switch ($type) {
            case Wechat::MSGTYPE_EVENT:
                //事件消息类型
                $event_type = $wx_data['Event'];
                switch ($event_type) {
                    case Wechat::EVENT_SUBSCRIBE:     //微信关注事件
                        $event_key = $wx_data['EventKey'];
                        if ($event_key != '') {
                            $event_key = strtoupper($event_key);
                            $event_key = str_replace('QRSCENE_', '', $event_key);
                            //带参二维码关注,跳转二维码事件
                            $this->qrcode($event_key,$wx_userinfo);
                            exit;
                        } else {
                            $this->wechat->text('Hi,'.$wx_userinfo['nickname'].'!欢迎关注五五科技!')->reply();exit;
                        }
                        break;
                    case Wechat::EVENT_SCAN:     //关注后二维码事件
                        if ($wx_data['EventKey'] != '') {
                            $event_key = strtoupper($wx_data['EventKey']);

                            $this->qrcode($event_key,$wx_userinfo);
                            exit;
                        }
                        break;
                }
                break;
            default:
                $this->wechat->text('Hi,'.$wx_userinfo['nickname'].'!欢迎关注五五科技!')->reply();exit;
                exit;
                break;
        }
    }
    /**
     * 二维码扫描回复
     * @param $qrkey    二维码所带参数
     * @param $userInfo  用户信息
     */
    public function qrcode($event_key,$wx_userinfo){
        if(strstr($event_key, 'LOGIN_')){
            $res = $this->login($event_key,$wx_userinfo);
            $data['openid'] = $wx_userinfo['openid'];
            $data['create_time'] = time();
            if($res){
                $data['project_name'] = "扫码登录成功";
                $data['url'] = C('DOMAIN').U('Home/Company/index');
                //发送微信模板消息
                $this->wxMsg->organSend(1,$data);exit;
            }else{
                $data['project_name'] = "扫码失败,请稍后再试";
                $this->wxMsg->organSend(1,$data);exit;
            }
        }
        exit;
    }
    //登录
    public function login($code,$userInfo){
        $user_id = $this->getUserId($userInfo);
        if(empty($user_id)){
            return false;
        }
        if(empty($userInfo['openid'])){
            return false;
        }
        $login_id=M('login')->field('id')->where(['openid'=>$userInfo['openid']])->getField('id');

        if(!$login_id){
            $data['openid'] = $userInfo['openid'];
            $data['uid'] = $user_id;
            $data['code'] = $code;
            $data['create_time'] = time();
            $res = M('login')->add($data);
        }else{
            $res = M('login')->where(['openid'=>$userInfo['openid']])->setField('code',$code);
        }
        if($res !== false){
            return true;
        }else{
            return false;
        }
    }

关联资源:
(一)、生成 微信Accesstoken 服务:



namespace Common\Service;
use Extend\WechatAuth;//下载地址
#1、使用前需要配置微信 APPID、APPSECRET、过期时间(默认6500秒,官方过期时间为7200秒)
#2、创建存储数据库 该类基于thinkphp3.2 框架开发 其他框架请适当修改操作数据库方法
class AccesstokenService {
    public function getAccessToken()
    {
        $appid = C('WX_APPID');//微信公众号APPID
        $appsecret = C('WX_APPSECRET');//微信公众号APPSECRET
        $accessTokenInfo = M('access_token')->order('expire desc')->find();
        if($accessTokenInfo && $accessTokenInfo['accesstoken']){
            if(time()<$accessTokenInfo['expire']){
                $accessToken['access_token'] = $accessTokenInfo['accesstoken'];
                $accessToken['jsapi_ticket'] = $accessTokenInfo['jsapi_ticket'];
            }else{
                //token 过期
                $accessToken = $this->getWechatAccess($appid,$appsecret);
            }
        }else{
            $accessToken = $this->getWechatAccess($appid,$appsecret);
        }
        return $accessToken;
    }
    //获取微信 access_token
    public function getWechatAccess($appid,$appsecret){
        $wechatAuth = new WechatAuth($appid, $appsecret);
        $s_accessToken = $wechatAuth->getAccessToken();
        $add['accesstoken'] = $s_accessToken['access_token'];
        $add['jsapi_ticket']= $this->getTicket($appid,$appsecret,$s_accessToken['access_token']);
        $add['expire'] = time()+6500;//过期时间戳 token有限期为7200 要及时更新token
        $this->delAccessToken();
        $addInfo = M('access_token')->add($add);
        if($addInfo){
            $return['access_token'] = $add['accesstoken'];
            $return['jsapi_ticket'] = $add['jsapi_ticket'];
        }
        return $return;
    }
    //获取 微信js Ticket
    public function getTicket($appid,$appsecret,$accessToken){
        $wechatAuth = new WechatAuth($appid, $appsecret,$accessToken);
        $returnTicket = $wechatAuth->getJsapiTicket();
        $ticket = $returnTicket['ticket'] ? $returnTicket['ticket']:0;
        return $ticket;
    }
    //删除token
    public function delAccessToken(){
        $deleWhere['expire'] = array('gt',0);
        M('access_token')->where($deleWhere)->delete();
    }

}

使用案例:


namespace Weixin\Controller;
use Common\Service\AccesstokenService;
public function getToken(){
    $accesstokenService = new AccesstokenService();
    $access= $accesstokenService->getAccessToken();
    $access_token = $access['access_token'];
}

(二)、Wechat.class.php 微信公众平台PHP-SDK
封装了微信公众号开发的基本功能 只给公众号互动的用户提供服务,指定用户提供服务请参考下方的WechatAuth类

    #代码片段
    const MSGTYPE_TEXT = 'text';
    const MSGTYPE_IMAGE = 'image';
    const MSGTYPE_LOCATION = 'location';
    const MSGTYPE_LINK = 'link';
    const MSGTYPE_EVENT = 'event';
    const MSGTYPE_MUSIC = 'music';
    const MSGTYPE_NEWS = 'news';
    const MSGTYPE_VOICE = 'voice';
    const MSGTYPE_VIDEO = 'video';
    const EVENT_SUBSCRIBE = 'subscribe';       //订阅
    const EVENT_UNSUBSCRIBE = 'unsubscribe';   //取消订阅
    const EVENT_SCAN = 'SCAN';                 //扫描带参数二维码
    const EVENT_LOCATION = 'LOCATION';         //上报地理位置
    const EVENT_MENU_VIEW = 'VIEW';                     //菜单 - 点击菜单跳转链接
    const EVENT_MENU_CLICK = 'CLICK';                   //菜单 - 点击菜单拉取消息
    const EVENT_MENU_SCAN_PUSH = 'scancode_push';       //菜单 - 扫码推事件(客户端跳URL)
    const EVENT_MENU_SCAN_WAITMSG = 'scancode_waitmsg'; //菜单 - 扫码推事件(客户端不跳URL)
    const EVENT_MENU_PIC_SYS = 'pic_sysphoto';          //菜单 - 弹出系统拍照发图
    const EVENT_MENU_PIC_PHOTO = 'pic_photo_or_album';  //菜单 - 弹出拍照或者相册发图
    const EVENT_MENU_PIC_WEIXIN = 'pic_weixin';         //菜单 - 弹出微信相册发图器
    const EVENT_MENU_LOCATION = 'location_select';      //菜单 - 弹出地理位置选择器
    const EVENT_SEND_MASS = 'MASSSENDJOBFINISH';        //发送结果 - 高级群发完成
    const EVENT_SEND_TEMPLATE = 'TEMPLATESENDJOBFINISH';//发送结果 - 模板消息发送结果
    const EVENT_KF_SEESION_CREATE = 'kfcreatesession';  //多客服 - 接入会话
    const EVENT_KF_SEESION_CLOSE = 'kfclosesession';    //多客服 - 关闭会话
    const EVENT_KF_SEESION_SWITCH = 'kfswitchsession';  //多客服 - 转接会话
    const EVENT_CARD_PASS = 'card_pass_check';          //卡券 - 审核通过
    const EVENT_CARD_NOTPASS = 'card_not_pass_check';   //卡券 - 审核未通过
    const EVENT_CARD_USER_GET = 'user_get_card';        //卡券 - 用户领取卡券
    const EVENT_CARD_USER_DEL = 'user_del_card';        //卡券 - 用户删除卡券
    ...此处省略好多字
    const CARD_MEMBERCARD_ACTIVATE        = '/card/membercard/activate?';      //激活会员卡
    const CARD_MEMBERCARD_UPDATEUSER      = '/card/membercard/updateuser?';    //更新会员卡
    const CARD_MOVIETICKET_UPDATEUSER     = '/card/movieticket/updateuser?';   //更新电影票(未加方法)
    const CARD_BOARDINGPASS_CHECKIN       = '/card/boardingpass/checkin?';     //飞机票-在线选座(未加方法)
    const CARD_LUCKYMONEY_UPDATE          = '/card/luckymoney/updateuserbalance?';     //更新红包金额
    const SEMANTIC_API_URL = '/semantic/semproxy/search?'; //语义理解
    ...此处也省略好多字
    ///微信摇一摇周边
    const SHAKEAROUND_DEVICE_APPLYID = '/shakearound/device/applyid?';//申请设备ID
    const SHAKEAROUND_DEVICE_SEARCH = '/shakearound/device/search?';//查询设备列表
    const SHAKEAROUND_DEVICE_BINDLOCATION = '/shakearound/device/bindlocation?';//配置设备与门店ID的关系
    const SHAKEAROUND_DEVICE_BINDPAGE = '/shakearound/device/bindpage?';//配置设备与页面的绑定关系
    const SHAKEAROUND_PAGE_ADD = '/shakearound/page/add?';//增加页面
    const SHAKEAROUND_PAGE_UPDATE = '/shakearound/page/update?';//编辑页面
    const SHAKEAROUND_PAGE_SEARCH = '/shakearound/page/search?';//查询页面列表
    const SHAKEAROUND_PAGE_DELETE = '/shakearound/page/delete?';//删除页面
    const SHAKEAROUND_USER_GETSHAKEINFO = '/shakearound/user/getshakeinfo?';//获取摇周边的设备及用户信息
    const SHAKEAROUND_STATISTICS_DEVICE = '/shakearound/statistics/device?';//以设备为维度的数据统计接口
    微信公众号基本功能都封装好了轻松调用

使用案例:



namespace Weixin\Controller;
use Think\Controller;
use Extend\Wechat;

/**
 * 微信主入口
 */
class IndexController extends Controller
{
    protected $wechat;
    public function _initialize()
    {
        //配置
        $options = array(
            'token' => C("WX_TOKEN"), //填写你设定的key
            'encodingaeskey' => C("WX_ENCODINGAESKEY"),//填写加密用的EncodingAESKey,如接口为明文模式可忽略
            'appid' => C("WX_APPID"), //填写高级调用功能的app id
            'appsecret' => C("WX_APPSECRET") //填写高级调用功能的密钥
        );
        $this->wechat = new Wechat($options);
    }
}

下载地址:
https://download.csdn.net/download/qq_16024861/10619807

(三)、WechatAuth类 封装了 微信消息及二维码类 可指定openid 发送消息

    #代码片段
    /* 消息类型常量 */
    const MSG_TYPE_TEXT     = 'text';
    const MSG_TYPE_IMAGE    = 'image';
    const MSG_TYPE_VOICE    = 'voice';
    const MSG_TYPE_VIDEO    = 'video';
    const MSG_TYPE_MUSIC    = 'music';
    const MSG_TYPE_NEWS     = 'news';
    const MSG_TYPE_LOCATION = 'location';
    const MSG_TYPE_LINK     = 'link';
    const MSG_TYPE_EVENT    = 'event';

    /* 二维码类型常量 */
    const QR_SCENE       = 'QR_SCENE';
    const QR_STR_SCENE   = 'QR_STR_SCENE';
    const QR_LIMIT_SCENE = 'QR_LIMIT_SCENE';
    const QR_LIMIT_STR_SCENE = 'QR_LIMIT_STR_SCENE';

使用案例:



namespace Weixin\Controller;

use Think\Controller;
use Extend\WechatAuth;
use Common\Service\AccesstokenService;

/**
 * 微信主入口
 */
class IndexController extends Controller
{

    protected $WechatAuth;
    protected $accessToken;

    public function _initialize()
    {
        $accesstokenService = new AccesstokenService();
        $access = $accesstokenService->getAccessToken();
        $this->accessToken = $access['access_token'];
        $appid = C("WX_APPID"); //填写高级调用功能的app id
        $appsecret = C("WX_APPSECRET"); //填写高级调用功能的密钥
        $this->WechatAuth = new WechatAuth($appid, $appsecret, $this->accessToken);
    }
    public function index(){
        $openid = 'oDz8p0nnhZyajdc7RhLWT3QeQX7c';
        //发送文本消息
        $this->WechatAuth->sendText($openid,"hello world!");
    }
}

下载地址:
https://download.csdn.net/download/qq_16024861/10619821

(四)打包下载
**三类合一(AccesstokenService、Wechat、WechatAuth)
几行代码实现微信公众号想要的功能,你值得拥有**
下载地址:
https://download.csdn.net/download/qq_16024861/10619358

(五)微信模板消息类
template.php 模板配置项
TemplenoticeService.class.php 模板类
第一步:在微信公众号模板管理添加要使用的模板
第二步:在模板配置项配置好模板如下:
如何用微信公众号二维码事件做扫码登陆_第1张图片
第三步:在模板消息类配置好每个类型对应发送哪个模板消息
如何用微信公众号二维码事件做扫码登陆_第2张图片
第四步:配置好根据类型选择模板id
如何用微信公众号二维码事件做扫码登陆_第3张图片
第五步:创建数据表 记录消息发送状态,发送失败支持重新发送

CREATE TABLE `send_log` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `openid` varchar(100) NOT NULL DEFAULT '' COMMENT '微信收件人openid',
  `template_id` varchar(100) NOT NULL DEFAULT '' COMMENT '微信template_id',
  `title` varchar(255) DEFAULT NULL COMMENT '标题',
  `content` text NOT NULL COMMENT '消息内容',
  `wechat_result` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '微信是否发送成功,0否,1是',
  `wechat_fail_reason` varchar(255) NOT NULL DEFAULT '' COMMENT '微信失败原因',
  `create_time` int(11) NOT NULL DEFAULT '0' COMMENT '创建时间',
  `url` varchar(150) DEFAULT NULL COMMENT '跳转url',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

使用案例:



namespace Weixin\Controller;

use Think\Controller;
use Extend\Wechat;
use Extend\WechatAuth;
use Common\Service\AccesstokenService;
use Common\Service\TemplenoticeService;
use Think\Log;

/**
 * 微信主入口
 */
class IndexController extends Controller
{
    protected $wxMsg;

    public function _initialize()
    {
        $this->wxMsg = new TemplenoticeService();
    }
    //发送类型为1的模板消息 
    //先在TemplenoticeService.class.php 模板类 找到1的类型
    //const WX_LOGIN = 1;   //微信登录 1为登陆类型 登陆类型模板id为1
    //安全登录提醒
       // '1' => array(
       //     'template_id' => 'vKsF0lYqpNcDQ4zzkgj_Nletqbjx6a1oPDNVGJi88so',
       //     'msg' => array(
       //         'first' => array('value'=>'%title%\n\r','color'=>"#55BBAA"),
       //         'keyword1' => array('value'=>'%project_name%','color'=>"#000000"),//登录方式
       //         'keyword2' => array('value'=>'%create_time%','color'=>"#000000"),//登录时间
       //     ),
       // ),
       //登陆类型有title、project_name、create_time变量 我们组装数组的时候需要设置数组参数
    public function index(){
        $data['openid'] = 'oDz8p0nnhZyajdc7RhLWT3QeQX7c';//必须 接收模板消息的用户openid
        $data['create_time'] = time();
        $data['project_name'] = "扫码登录成功";
        $data['url'] = C('DOMAIN').U('Home/Company/index');//可无
        $this->wxMsg->organSend(1,$data);exit;//消息发送后不管失败还是成功会记录到send_log表
    }
    //重发id为1的模板消息
    public function emailSend(){
          $id = 1;
          if(empty($id)){
              $this->ajaxError('参数不能为空');
          }
          $info = M('send_log')->find($id);
          if(empty($info)){
              $this->ajaxError('邮件不存在');
          }
          $res = $this->wxMsg->sendAgain($info);
          if(isset($res) && $res['status'] == 1){
              $save['wechat_result'] = 1;
              $save['wechat_fail_reason'] = '';
              M('send_log')->where(['id'=>$id])->save($save);
              $this->ajaxSuccess('发送成功');
          }else{
              $save['wechat_result'] = 0;
              $save['wechat_fail_reason'] = $res['info'];
              M('send_log')->where(['id'=>$id])->save($save);
              $this->ajaxError('失败原因:'.$res['info']);
          }
    }
}

资源包含:1、生成 微信Accesstoken 服务;2、WechatAuth类 封装了 微信消息及二维码类 可指定openid 发送消息;3、微信模板消息类
下载地址:
https://download.csdn.net/download/qq_16024861/10620060

你可能感兴趣的:(微信公众号)