1. 程式人生 > >微信授權登入(PHP)

微信授權登入(PHP)

主要是在專案中遇到網頁授權登入這個需求,就對此做些總結記錄。

OAuth2.0授權
OAuth是一個開放協議,允許使用者讓第三方應用以安全且標準的方式獲取該使用者在某一網站、移動或桌面應用上儲存的個人資訊,而無需將使用者名稱和密碼提供給第三方應用。常見微信、QQ登入,省去管理賬戶的麻煩,也不會造成使用者的流失。

開啟微信的官方文件,會看到網頁授權一些說明。(有點摸不著頭腦,主要是當時沒能關聯起來,微信文件每次看都那麼鬱悶!!!)

來了解下授權的模式,官方說的詳細(這得仔細閱讀下):
關於網頁授權的兩種scope的區別說明
1、以snsapi_base為scope發起的網頁授權,是用來獲取進入頁面的使用者的openid的,並且是靜默授權並自動跳轉到回撥頁的。使用者感知的就是直接進入了回撥頁(往往是業務頁面)
2、以snsapi_userinfo為scope發起的網頁授權,是用來獲取使用者的基本資訊的。但這種授權需要使用者手動同意,並且由於使用者同意過,所以無須關注,就可在授權後獲取該使用者的基本資訊。
3、使用者管理類介面中的“獲取使用者基本資訊介面”,是在使用者和公眾號產生訊息互動或關注後事件推送後,才能根據使用者OpenID來獲取使用者基本資訊。這個介面,包括其他微信介面,都是需要該使用者(即openid)關注了公眾號後,才能呼叫成功的。

實現思路

enter description here

101637543016285

  1. 在微信公眾號中設定網頁授權域名;
  2. 使用者開啟登入頁,進入網頁授權頁面url;
  3. 微信詢問使用者是否同意授權給微信公眾號;(snsapi_base 靜默授權無此步驟,並且此模式snsapi_userinfo需關注微信公眾號)
  4. 使用者同意授權(snsapi_base靜默授權直接默認同意)
  5. 回撥code,帶code引數請求微信,換取網頁授權access_token(此步獲取openid,微信使用者的唯一標識)
  6. 通過【獲取使用者基本資訊】介面,引數access_token(和上面的不同,普通的access_token)和openid,判斷是否繫結微信公眾號,未繫結,跳轉繫結頁。(此步驟snsapi_base無需,當然這個步驟可以去掉,視情況而定,像我專案就有這要求,唉)
  7. 將openid帶入登入頁,商戶伺服器檢測當前openid是否存在資料庫使用者記錄中
  8. 不存在openid記錄,登入使用者,商戶伺服器將openid存入使用者表中;(存在openid記錄跳過此步驟)
  9. openid記錄存在,則拉取使用者資訊,存入會話,完成登入;

以上是本人實際專案中的做法,除此之外我們的介面做了簽名驗證,有一定安全性。僅供參考,總覺得有更好的思路,希望大家指出。

話不多說,貼出實現邏輯程式碼:
商戶端登入

  public function actionLogin()
    {  
        session_start();
        $_SESSION['openid'] =  empty( $_SESSION['openid'] ) ? $_GET['openid'] : $_SESSION['openid'];
        if(!$_GET['openid']){
            $this->apiget('WeixinServer/ScopeRedirectUriAppid',array('sign'=>$this->sign,'sourcetype'=>7,'data' => ''));
            header("Location:".Yii::app()->params['apipath'].'/WeixinServer/ScopeRedirectUriAppid?sign='.$this->sign.'&sourcetype=7' );
            exit;
        }
        if($_SESSION['openid']){
            //判斷繫結公眾號
            $jssdk = new JSSDK();
            $access_token = $jssdk->getAccessToken();
            $url = "https://api.weixin.qq.com/cgi-bin/user/info?access_token={$access_token}&openid={$_SESSION['openid']}&lang=zh_CN";
            $UserInfo = json_decode($this->dogetCurl($url),1);
            if( empty($UserInfo['subscribe']) ){
                //跳轉關注頁
                header("Location:https://mp.weixin.qq.com/mp/profile_ext?action=home&__biz=MzA3Mzg2MjMyNw==&scene=124#wechat_redirect" );
               die;
            }

            //微信登入
            $WeixinLogin = $this->apiget('WeixinServer/WeixinLogin', array('sign'=>$this->sign,'sourcetype'=>7,'openid'=>$_SESSION['openid']));
            if( $WeixinLogin['error']==1){
                return $this->render($this->act);
            }
            $this->WeinxinLogin($WeixinLogin);
			die;
        }
        $this->render($this->act);
    }
	
	##微信授權成功 寫入session,跳轉首頁
    public function WeinxinLogin( $data=array() ){
        $_SESSION['user'] = $data['data'];

        $this->redirect('/index/index');
    }
	
	##curl請求
	public function apiget($path, $param=array()){
		$url = Yii::app()->params['apipath'].$path;
		$curl = curl_init();
		curl_setopt($curl, CURLOPT_USERAGENT, '3');	//User-Agent
        curl_setopt($curl, CURLOPT_URL, $url);
		curl_setopt($curl, CURLOPT_POST, 1);
		curl_setopt($curl, CURLOPT_POSTFIELDS, $param);	
		curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
        $return = curl_exec($curl);
		curl_close($curl);
		$j = json_decode($return, 1);
		return $return;
	}

WeixinServer 處理微信授權

<?php

class WeixinServerController extends Controller
{
    public function __construct()
    {
     	//todo  驗證簽名
    }
	
	public function error($msg){
			header("Content-type: application/json");
			$o['time'] = "".time();
			$o['error'] = '1';
			$o['errorMsg'] = $msg;
			echo json_encode($o);die;
	}
	
    public function Login($user=array()){
      //todo 獲取使用者資訊
	  
    }
	
    ##=====================================微信授權========================================##
    ##微信授權登入
    public function actionWeixinLogin(){
        if( empty($_POST['openid']) ) $this->error('openid為空');
		//todo 通過openid查詢使用者
        $user = DB::get_one("SELECT *  FROM {{user}} WHERE openid='{$_POST['openid']}' "); 
        if( !$user )$this->error('openid不存在');
        $userinfo =  $this->Login($user['uid']); 
        $this->out($userinfo);
    }

    ##微信授權 獲取code
    public function actionScopeRedirectUriAppid(  ){
        $APPID = "XXXXXXXXXXXX";
        $REDIRECT_URI=  'http://'.$_SERVER['HTTP_HOST'].'/WeixinServer/WeixinOpenidCallback';
        $scope='snsapi_base';  //手動授權snsapi_userinfo   靜默授權snsapi_base

        $url='https://open.weixin.qq.com/connect/oauth2/authorize?appid='.$APPID.'&redirect_uri='.urlencode($REDIRECT_URI).'&response_type=code&scope='.$scope.'&state=scene#wechat_redirect';
        header("Location:{$url}" );
    }
	
    ##微信回撥,獲取openid
    public function actionWeixinOpenidCallback(){
        if( $code= Yii::app()->request->getParam('code') ){
            $APPID = "XXXXXXXXXXXX";
            $SECRET = "XXXXXXXXXXXX";
            $url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid={$APPID}&secret={$SECRET}&code={$code}&grant_type=authorization_code";
            $UserOpenidArr = json_decode($this->dogetCurl($url),1);
            if( empty($UserOpenidArr ['openid']) ) {
                print_r( $UserOpenidArr );
                die();
            }
            header("Location:http://XXXXXXXX/index/login?openid={$UserOpenidArr ['openid']}" );
        }else{
            die("微信授權失敗");
        }
    }

    public function dogetCurl( $url ='' )
    {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_HEADER, 0);
        curl_setopt ( $ch, CURLOPT_HTTPHEADER, array( 'Connection: Keep-Alive', 'Keep-Alive: 300' ));
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        $data = curl_exec($ch);
        curl_close ( $ch );
        return $data;
    }

}

程式碼結合實現思路,大致思想清楚就好實現了,希望對大家有幫助(程式碼寫的爛,將就看吧)。

—— 路漫漫其修遠兮 吾將上下而求索