banner
阿珏酱

阿珏酱

いつもとは逆の電車に乗り、見たこともない風景を見に行く
twitter
github
facebook
bilibili
zhihu
steam_profiles
youtube

WeChat Authorization Login

Tips: When you see this prompt, it means that the current article has been migrated from the original emlog blog system to here. The publication date of the article is quite old, and the formatting and content may not be complete. Please understand.

WeChat Authorization Login

Date: 2019-4-5 Ajuo Code Tweaking Views: 1874 times Comments: 1

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

WeChat's authorization login is similar to that of platforms like QQ and Sina, both using Oauth OAuth2.0 authentication method.
WeChat authorization is divided into two types:
  1. Silent Authorization
  2. Popup Authorization, which requires user manual consent
Explanation of the differences between the two scopes
  1. The web authorization initiated with snsapi_ base as the scope is used to obtain the openid of the user entering the page, and it is a silent authorization that automatically redirects to the callback page. What the user perceives is that they directly enter the callback page (often the business page).
  2. The web authorization initiated with snsapi_userinfo as the scope is used to obtain the user's basic information. However, this authorization requires user manual consent, and since the user has consented, there is no need to pay attention, and the user's basic information can be obtained after authorization.
The "Get User Basic Information Interface" in the user management interface can only be called after the user interacts with the public account through message exchange or after the event push of following the account, based on the user's OpenID. This interface, along with other WeChat interfaces, can only be successfully called after the user (i.e., openid) has followed the public account.

Specifically, the web authorization process is divided into four steps:
  1. Guide the user to the authorization page to agree to the authorization and obtain the code.
  2. Exchange the code for the web authorization access_token (different from the access_token in basic support).
  3. If necessary, developers can refresh the web authorization access_token to avoid expiration.
  4. Obtain user basic information using the web authorization access_token and openid (supports UnionID mechanism).

The following is the encapsulated WeChat operation class, which requires two data tables to save access_token and ticket. Due to their certain validity period and daily request limits, developers need to save them themselves.

<?php
/**
*   WeChat operation table
*   wxtoken table structure
*   id
*   access_token
*   addtime
*   wxticket table structure
*   id
*   ticket
*   addtime
*/
class WX {
	private $appid;
	private $appserect;
	private $curl;
	private $msg;
	protected $errs = array(
		'-1' => 'System busy, please try again later',
		'0' => 'Request successful',
		'40001' => 'AppSecret error or AppSecret does not belong to this public account, please confirm the correctness of AppSecret',
		'40002' => 'Please ensure that the grant_type field value is client_credential',
		'40164' => 'The IP address calling the interface is not in the whitelist, please set it in the interface IP whitelist.',
	);
	function __construct($appid, $appserect) {
		$this->appid = $appid;
		$this->appserect = $appserect;
		$this->curl = new Curl();
	}
	/*
	WeChat web authorization login  needs to be set in the public account - function settings - web authorization domain name
	Step 1: User agrees to authorize and obtains code
	scope : snsapi_base can only get openid and directly redirect
	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;
	}
	/*
	Step 2: Exchange the code for web authorization 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 = "Failed to obtain token";
			return false;
		}
		$result = json_decode($result, true);
		if ($result['errcode']) {
			$this->msg = $result['errmsg'];
			return false;
		}
		return $result;
	}
	// Step 3: Refresh access_token (if needed)  Get openid through code $type 0 silent authorization 1 popup authorization
	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);
			// This interface has issues, forcing file header display
			$return = file_get_contents($url);
			if (!$return) {
				$this->msg = 'Failed to obtain user information';
				return false;
			}
			$return = json_decode($return, true);
			if (!$return) {
				$this->msg = 'Failed to return user information';
				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' => "WeChat User_" . 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;
		}
	}
	/*
	Public account security center set IP whitelist
	The globally unique interface calling credential for the public account, the public account needs to use access_token when calling each interface. Developers need to keep it properly. The storage of access_token must retain at least 512 characters of space. The current validity period of access_token is 2 hours, and it needs to be refreshed regularly. Repeated acquisition will cause the previously obtained access_token to become invalid.
	*/
	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 = "Unable to obtain token content";
				return false;
			}
			$result = json_decode($result, true);
			if (!$result) {
				$this->msg = "Failed to parse token content";
				return false;
			}
			if ($result['access_token']) {
				C::t(PT_WXTOKEN)->addToken($result['access_token'], $type);
				return $result['access_token'];
			} else {
				$this->msg = "Failed to obtain token";
				return false;
			}
		}
	}
	// Get js ticket  needs to be set in the public account - function settings - JS interface security domain name settings
	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 = "Unable to obtain js ticket";
				return false;
			}
			$result = json_decode($result, true);
			if (!$result) {
				$this->msg = "Failed to parse js ticket content";
				return false;
			}
			if ($result['ticket']) {
				C::t(PT_WXTICKET)->addTicket($result['ticket']);
				return $result['ticket'];
			} else {
				$this->msg = "Failed to obtain js ticket";
				return false;
			}
		}
	}
	// js sdk ticket signature current webpage URL, excluding # and the part after it
	public function jsSign($data) {
		// 1. All parameters to be signed are sorted in ascending order by ASCII code of field names (dictionary order)
		ksort($data);
		// 2. The URL key-value pair format (i.e., key1=value1&key2=value2…) is concatenated into string string1 using the original value without URL escaping
		$string1 = $this->ToUrlParams($data);
		// echo "string1:{$string1}<br/>";
		// 3. SHA1 encryption is performed on string1
		$sign = sha1($string1);
		// echo "signature:{$sign}<br/>";
		return $sign;
	}
	// Get message content
	public function getMsg() {
		return $this->msg;
	}
	/**
	* Format parameters into url parameters
	*/
	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;
	}
}
?>
// WeChat login
function wxlogin() {
	global $_G,$identifier,$config,$wx;
	if (!$_G['uid']) {
		if ($_GET['state']) {
			//Callback
			$member = $wx->getUserInfo($_GET['code']);
			if (!$member) {
				exit($wx->getMsg());
			}
			if (!function_exists("setloginstatus")) {
				include_once libfile('function/member');
			}
			// Set login status $wx
			setloginstatus($member, 2592000);
			checkfollowfeed();
			$_G['uid'] = $member['uid'];
			$_G['member'] = $member;
		} else {
			//Request authorization, encode parameters
			$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;
}

User Comments:

image Headline News 2 years ago (2019-04-11)
The article is good, let's support it.

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.