微信授權登入

阿珏酱發表於2024-05-20

Tips:當你看到這個提示的時候,說明當前的文章是由原emlog部落格系統搬遷至此的,文章釋出時間已過於久遠,編排和內容不一定完整,還請諒解`

微信授權登入

日期:2019-4-5 阿珏 折騰程式碼 瀏覽:1874次 評論:1條

文件: https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421135319

微信的授權登入和QQ、新浪等平臺的授權登入都大同小異,均採用 Oauth OAuth2.0鑑權方式。
微信授權分為兩種:
  1. 靜默授權
  2. 彈窗授權,需要使用者手動同意
兩種scope的區別說明
  1. 以snsapi_ base為scope發起的網頁授權,是用來獲取進入頁面的使用者的openid的,並且是靜默授權並自動跳轉到回撥頁的。使用者感知的就是直接進入了回撥頁(往往是業務頁面)
  2. 以snsapi_userinfo為scope發起的網頁授權,是用來獲取使用者的基本資訊的。但這種授權需要使用者手動同意,並且由於使用者同意過,所以無須關注,就可在授權後獲取該使用者的基本資訊。
使用者管理類介面中的“獲取使用者基本資訊介面”,是在使用者和公眾號產生訊息互動或關注後事件推送後,才能根據使用者OpenID來獲取使用者基本資訊。這個介面,包括其他微信介面,都是需要該使用者(即openid)關注了公眾號後,才能呼叫成功的。

具體而言,網頁授權流程分為四步:
  1. 引導使用者進入授權頁面同意授權,獲取code
  2. 透過code換取網頁授權access_token(與基礎支援中的access_token不同)
  3. 如果需要,開發者可以重新整理網頁授權access_token,避免過期
  4. 透過網頁授權access_token和openid獲取使用者基本資訊(支援UnionID機制)
以下是封裝的微信操作類,需要用到兩個資料表,用於儲存access_token、ticket,由於他們具有一定有效期,且每天請求數有上限,所以開發者需自行儲存
<?php
/**
*   微信操作表
*   wxtoken 表結構
*   id
*   access_token
*   addtime
*   wxticket 表結構
*   id
*   ticket
*   addtime
*/
class WX {
	private $appid;
	private $appserect;
	private $curl;
	private $msg;
	protected $errs = array(
		'-1' => '系統繁忙,此時請開發者稍候再試',
		'0' => '請求成功',
		'40001' => 'AppSecret錯誤或者AppSecret不屬於這個公眾號,請開發者確認AppSecret的正確性',
		'40002' => '請確保grant_type欄位值為client_credential',
		'40164' => '呼叫介面的IP地址不在白名單中,請在介面IP白名單中進行設定。',
	);
	function __construct($appid, $appserect) {
		$this->appid = $appid;
		$this->appserect = $appserect;
		$this->curl = new Curl();
	}
	/*
	微信網頁授權登入  需要在公眾號設定 - 功能設定 - 網頁授權域名
	第一步:使用者同意授權,獲取code
	scope : snsapi_base 只能獲取openid 直接跳轉
	snsapi_userinfo
	*/
	public function getCode($redirect_uri, $scope = 'snsapi_userinfo',$state = '1') {
		$url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid={$this->appid}&redirect_uri={$redirect_uri}&response_type=code&scope={$scope}&state={$state}#wechat_redirect";
		header("Location:{$url}");
		exit;
	}
	/*
	第二步:透過code換取網頁授權access_token
	*/
	public function getAccessTokenByCode($code) {
		$url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid={$this->appid}&secret={$this->appserect}&code={$code}&grant_type=authorization_code";
		// exit($url);
		// $curl = new Curl();
		$result = $this->curl->doGet($url);
		if (!$result) {
			// $this->curl->getError()
			$this->msg = "獲取token失敗";
			return false;
		}
		$result = json_decode($result, true);
		if ($result['errcode']) {
			$this->msg = $result['errmsg'];
			return false;
		}
		return $result;
	}
	// 第三步:重新整理access_token(如果需要) 透過code 獲取openid $type 0靜默授權 1彈窗授權
	public function getUserInfo($code, $type = 0, $lang = 'zh_CN ') {
		$result = $this->getAccessTokenByCode($code);
			if (!$result) {
			return false;
		}
		$member = C::t(PT_USER)->getByOpenid($result['openid']);
	if ($member) {
		return $member;
	} else {
		if ($type) {
			$url = "https://api.weixin.qq.com/sns/userinfo?access_token={$result['access_token']}&openid={$result['openid']}&lang={$lang}";
			// $return = $this->curl->doGet($url);
			// 這介面有病 強制顯示檔案頭
			$return = file_get_contents($url);
			if (!$return) {
				$this->msg = '獲取使用者資訊失敗';
				return false;
			}
			$return = json_decode($return, true);
			if (!$return) {
				$this->msg = '獲取使用者資訊返回失敗';
				return false;
			}
			// file_put_contents('ccc.txt',print_r($return,true),FILE_APPEND);
			$data = array(
				'openid' => $return['openid'],
				'name' => $return['nickname'],
				'sex' => $return['sex'],
				'province' => $return['province'],
				'city' => $return['city'],
				'country' => $return['country'],
				'img' => $return['headimgurl'],
				'bindtel' => 0,
			);
		} else {
			$data = array(
				'openid' => $result['openid'],
				'username' => "微信使用者_" . random(6,1)
			);
		}
		$name = rand(100000, 1000000000);
		$e = $name . "@qq.com";
		$password = $e;
		$id = UserAddEdit(0, $data['username'], $password, $e,10,0,"", $msg);
		if ($id <= 0) {
			$this->msg = $msg;
			return false;
		}
		C::t(PT_USER)->update($data, $id);
		$member = C::t(PT_USER)->get($id);
		return $member;
		}
	}
	/*
	公眾號 安全中心 設定IP白名單
	公眾號的全域性唯一介面呼叫憑據,公眾號呼叫各介面時都需使用access_token。開發者需要進行妥善儲存。access_token的儲存至少要保留512個字元空間。access_token的有效期目前為2個小時,需定時重新整理,重複獲取將導致上次獲取的access_token失效。
	*/
	public function getAccessToken($type) {
		$addtime = TIMESTAMP - 7200;
		$url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={$this->appid}&secret={$this->appserect}";
		$row = C::t(PT_WXTOKEN)->getNew($addtime, $type);
		if ($row) {
			return $row['access_token'];
		} else {
			$result = $this->curl->doGet($url);
			if (!$result) {
				$this->msg = "無法獲取令牌內容";
				return false;
			}
			$result = json_decode($result, true);
			if (!$result) {
				$this->msg = "解析令牌內容失敗";
				return false;
			}
			if ($result['access_token']) {
				C::t(PT_WXTOKEN)->addToken($result['access_token'], $type);
				return $result['access_token'];
			} else {
				$this->msg = "獲取令牌失敗";
				return false;
			}
		}
	}
	// 獲取js票據  需要在公眾號設定 - 功能設定 - JS介面安全域名設定
	public function getJsTicket() {
		$addtime = TIMESTAMP - 7200;
		$row = C::t(PT_WXTICKET)->getNew($addtime);
		if ($row) {
			return $row['ticket'];
		} else {
			$token = $this->getAccessToken();
			if (!$token) {
				return false;
			}
			$url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token={$token}&type=jsapi";
			$result = $this->curl->doGet($url);
			if (!$result) {
				$this->msg = "無法獲取js票據";
				return false;
			}
			$result = json_decode($result, true);
			if (!$result) {
				$this->msg = "解析js票據內容失敗";
				return false;
			}
			if ($result['ticket']) {
				C::t(PT_WXTICKET)->addTicket($result['ticket']);
				return $result['ticket'];
			} else {
				$this->msg = "獲取js票據失敗";
				return false;
			}
		}
	}
	// js sdk 票據簽名 當前網頁的URL,不包含#及其後面部分
	public function jsSign($data) {
		// 1.所有待簽名引數按照欄位名的ASCII 碼從小到大排序(字典序)
		ksort($data);
		// 2.URL鍵值對的格式(即key1=value1&key2=value2…)拼接成字串string1 採用原始值,不進行URL 轉義
		$string1 = $this->ToUrlParams($data);
		// echo "string1:{$string1}<br/>";
		// 3.對string1做sha1加密
		$sign = sha1($string1);
		// echo "signature:{$sign}<br/>";
		return $sign;
	}
	// 獲取訊息內容
	public function getMsg() {
		return $this->msg;
	}
	/**
	* 格式化引數格式化成url引數
	*/
	public function ToUrlParams($data) {
		$buff = "";
		foreach ($data as $k => $v) {
			if ($k != "sign" && $v != "" && !is_array($v)) {
				$buff .= $k . "=" . $v . "&";
			}
		}
		$buff = trim($buff, "&");
		return $buff;
	}
}
?>
// 微信登入
function wxlogin() {
	global $_G,$identifier,$config,$wx;
	if (!$_G['uid']) {
		if ($_GET['state']) {
			//回撥
			$member = $wx->getUserInfo($_GET['code']);
			if (!$member) {
				exit($wx->getMsg());
			}
			if (!function_exists("setloginstatus")) {
				include_once libfile('function/member');
			}
			// 設定登入狀態$wx
			setloginstatus($member, 2592000);
			checkfollowfeed();
			$_G['uid'] = $member['uid'];
			$_G['member'] = $member;
		} else {
			//請求授權 對引數編碼
			$redirect = urlencode(getProtocol() . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
			$wx->getCode($redirect, 'snsapi_base');
		}
	}
}
function getProtocol() {
	return is_HTTPS() ? 'https://' : 'http://';
}
function is_HTTPS() {  if ($_SERVER['HTTPS'] === 1 || $_SERVER['HTTPS'] === 'on' || $_SERVER['SERVER_PORT'] == 443) {
		return true;
	}
	return false;
}

本部落格所有文章 如無特別註明 均為原創。 作者: 阿珏 複製或轉載請 以超連結形式 註明轉自 阿珏部落格
原文地址《 微信授權登入

網友評論:

頭條新聞 2年前 (2019-04-11)
文章不錯支援一下吧

相關文章