1. 程式人生 > >微信網站應用一鍵登入--Thinkphp

微信網站應用一鍵登入--Thinkphp

實現步驟:

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);//寫入到資料庫中,返回的是插入id
			cookie('username',$user['nickname']);
		    cookie('memberId', $memberId);
           
        }
		
		
		
        //session('userInfo', $userinfo);//寫入session
		redirect("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/