微信网站应用一键登录--Thinkphp

来源:互联网 发布:郑州的外企知乎 编辑:程序博客网 时间:2024/06/05 05:41

实现步骤:

1.注册微信开放平台https://open.weixin.qq.com,一定要清楚微信开放平台和微信公众平台是分别独立的,不能共用。

2.登录进入——管理中心,网站应用,创建网站应用。填写申请,企业还要盖章,然后设置域名,最后交300元保护费。成功通过验证。获得appid和appSecret两个参数。
3.现在可以在web端里写登录控制器了。
4.微信网站登录的文档在https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419316505&token=41ab5f757248bbbdcc2aad1a6d52b49fdc19579e&lang=zh_CN。
5.微信登录请求,其实你可以当成是个url跳转。https://open.weixin.qq.com/connect/qrconnect?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
参数 是否必须 说明
appid 是 应用唯一标识
redirect_uri 是 重定向地址,需要进行UrlEncode
response_type 是 填code
scope 是 应用授权作用域,拥有多个作用域用逗号(,)分隔,网页应用目前仅填写snsapi_login即可
state 否 用于保持请求和回调的状态,授权请求后原样带回给第三方。该参数可用于防止csrf攻击(跨站请求伪造攻击),建议第三方带上该参数,可设置为简单的随机数加session进行校验

把appid参数传给开放平台。链接页面会显示一个二维码。

6.用户扫码二维码,扫码成功后,会跳转回你传的域名地址。
同时域名后面会带有code和state参数。这个code则是我们需要拿到的钥匙
redirect_uri?code=CODE&state=STATE
7.在redirect_uri跳转的页面或者控制器中,接收code值
code每次会生成一个,用后即会销毁,也就是你不能不停跳转。
8.通过appid、appSecret还有code值,请求open的access_token接口,获得access_token。

"access_token":"ACCESS_TOKEN", 
"expires_in":7200, 
"refresh_token":"REFRESH_TOKEN",
"openid":"OPENID", 
"scope":"SCOPE",
"unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"
}

参数 说明
access_token 接口调用凭证
expires_in access_token接口调用凭证超时时间,单位(秒)
refresh_token 用户刷新access_token
openid 授权用户唯一标识
scope 用户授权的作用域,使用逗号(,)分隔
unionid 当且仅当该网站应用已获得该用户的userinfo授权时,才会出现该字段。

这里解释一下,access_token是接口凭证,请求接口需要带上,时间为2个小时。openid是获取用户信息的参数,就如username。而unionid则是uid,用户的唯一ID。
9.拿到token和openid后,可以通过UserInfo接口获得用户数据。https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID
正确的Json返回结果:

"openid":"OPENID",
"nickname":"NICKNAME",
"sex":1,
"province":"PROVINCE",
"city":"CITY",
"country":"COUNTRY",
"headimgurl": "http://wx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/0",
"privilege":[
"PRIVILEGE1", 
"PRIVILEGE2"
],
"unionid": " o6_bmasdasdsad6_2sgVt7hMZOPfL"

}
10.基本上流程就是这样。

流程完了就描述下问题。
1.如果第一步跳转到微信接口时,出现“scope参数错误”,说明appid错误或者你没交保护费。用微信公众号的appid没用
2.请求token的时候,需要通过cURL来抓取,CURL抓取时普遍会出现抓取不到的问题,具体没用深究,估计是https的抓取方式和http不一样,写了个httpGet方法实现了抓取,抓取后内容为json数据,需要decode一下转化为数组
3.为了实现与手机端用户一致性,我们需要记录openid以及unionid。公众号与开放平台的openid是不一样的,唯一相同的unionid。但是这两个openid都能获取到用户信息。我建议除了用户表以外,加一个第三方登录表,字段为 id,uid,type,openid,unionid,refresh_token。type 1是微信端,2是PC端。unionid存在时,就不需要再创建一条用户信息。信息获取后创建session或者cookie
4.为防止csrf跨站请求,state我加入了一个随机数,这个随机数存到session中,当用户扫码确认后,返回时,如果不一致即会被认为跨站请求伪造攻击

<?php/** * Created by PhpStorm. * function: 处理第三方登录:微信登录 * User: yule * Date: 2016/4/29 0029 * Time: 下午 6:48 */   namespace Home\Controller;use Think\Controller;class LoginApiController extends Controller{    private $_appId;    private $_appSecret;    private $_webRoot;    private $_openUrlQrc;    private $_openUrlToken;    private $_openUrlUserInfo;    public function __construct()    {     parent::__construct();//修改成自己的        $this->_appId = 'wx836a5fd61d0a420f';//开放平台网站应用        $this->_appSecret = '6293594d396c450b32eb71da5caa9197';        $this->_webRoot = 'http://www.volunteerinaustralia.com/index.php/Home/LoginApi/wxCheck';//返回的域名网址,必须跟网站应用的域名网址相同        $this->_openUrlQrc = 'https://open.weixin.qq.com/connect/qrconnect';//申请二维码接口        $this->_openUrlToken = 'https://api.weixin.qq.com/sns/oauth2/access_token';//申请token接口        $this->_openUrlUserInfo = 'https://api.weixin.qq.com/sns/userinfo';//申请用户信息接口    }     public function index(){    }    /**     * 验证微信扫码后的用户数据     */    public function wxCheck(){        $code = I('code');//只能使用1次即销毁        $state = I('state');        if($state != $_SESSION['wx_state']){            $this->error("请进入官网扫描二维码",'/index.php/Home/Index/login');            exit();        }        session('wx_state',null);//清除这个session        //获取access_token和openid信息,还有用户唯一标识unionid        $ken = $this->wxToken($code);//:access_token,expires_in,refresh_token,openid,scope,unionid                if($ken['errcode'] == 40029){            $this->error("code参数已经过期");        }//判断是否已存在        $map['openid'] = $ken['openid'];$map['unionid'] = $ken['unionid'];        $Member = M('member');//这个自己写一下查询数据库        $res = $Member->where($map)->select();//查询openid是否存在,而PC和微信端 openid不一致,只有unionid才是唯一标识        if($res){cookie('username',$res[0]['username']);    cookie('memberId',$res[0]['id']);        }         else{            $user = $this->wxUserInfo($ken['access_token'],$ken['openid']);//获取用户信息            $data = array(                'openid' => $user['openid'],                'unionid' => $user['unionid'],                'username' => $user['nickname'],                'password' => '微信用户'.$this->getRandChar(8),                //'updated' => time(),                'pubdate' => date("Y-m-d H:i:s"),            );            $memberId = $Member->add($data);//写入到数据库中,返回的是插入idcookie('username',$user['nickname']);    cookie('memberId', $memberId);                   }        //session('userInfo', $userinfo);//写入sessionredirect("http://www.volunteerinaustralia.com/index.php/Home/Index/member");    }    /**     * 提交微信登录请求     */    public function wxLogin(){        $stats = $this->getRandChar(16);//该参数可用于防止csrf攻击(跨站请求伪造攻击)        session('wx_state',$stats);//把随机字符串写入session,验证时对比        $url = $this->_openUrlQrc.'?appid='.$this->_appId.'&redirect_uri='.urlencode($this->_webRoot).'&response_type=code&scope=snsapi_login&state='.$stats;        redirect($url);//跳转到扫码    }    //生成随机数,length长度    function getRandChar($length){        $str = null;        $strPol = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz";        $max = strlen($strPol)-1;        for($i=0;$i<$length;$i++){            $str.=$strPol[rand(0,$max)];//rand($min,$max)生成介于min和max两个数之间的一个随机整数        }        return $str;    }    //CURL获取url返回值    function httpGet($url){        $oCurl = curl_init();//实例化        if(stripos($url,"https://")!==FALSE){            curl_setopt($oCurl, CURLOPT_SSL_VERIFYPEER, FALSE);            curl_setopt($oCurl, CURLOPT_SSL_VERIFYHOST, FALSE);        }        curl_setopt($oCurl, CURLOPT_URL, $url);        curl_setopt($oCurl, CURLOPT_RETURNTRANSFER, 1 );//是否返回值,1时给字符串,0输出到屏幕        $sContent = curl_exec($oCurl);//获得页面数据        $aStatus = curl_getinfo($oCurl);//获取CURL连接数据的信息        curl_close($oCurl);//关闭资源        //获取成功        $output_array = json_decode($sContent,true);//转换json格式        if(intval($aStatus["http_code"])==200){            return $output_array;        }else{            return false;        }    }      //获取token信息    public function wxToken($code){        $url = $this->_openUrlToken.'?appid='.$this->_appId.'&secret='.$this->_appSecret.'&code='.$code.'&grant_type=authorization_code';        $sContent = $this->httpGet($url);//获取token数据        return $sContent;    }    //延长token时间,默认token两个小时    public function wxrefresh($refresh){        $url = 'https://api.weixin.qq.com/sns/oauth2/refresh_token?appid='.$this->_appId.'&grant_type=refresh_token&refresh_token='.$refresh;        return $this->httpGet($url);    }     //检验token授权是否有效    public function wxchecktoken($token,$openid){       $url = 'https://api.weixin.qq.com/sns/auth?access_token='.$token.'&openid='.$openid;        return $this->httpGet($url);    }    //获取微信用户个人信息,但公众号和开放平台opendid 会不一样,unionid是用户唯一标识    public function wxUserInfo($token,$openid){        $url = $this->_openUrlUserInfo.'?access_token='.$token.'&lang=zh-CN&openid='.$openid;        return $this->httpGet($url);    }}  
作品网址:http://www.volunteerinaustralia.com/
0 0