Documentation: https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421135319
The authorized login of WeChat is similar to the authorized login of QQ, Sina and other platforms, and both adopt the OauthOAuth2.0 authentication method.
There are two types of WeChat authorization:
- Silent authorization
- Pop-up authorization requires manual consent from the user.
Explanation of the differences between the two scopes
- Web page authorization initiated with snsapi_base as the scope is used to obtain the openid of the user who enters the page, and is authorized silently and automatically jumps to the callback page. What the user perceives is that they directly enter the callback page (often a business page)
- Web page authorization initiated with snsapi_userinfo as the scope is used to obtain the user’s basic information. However, this kind of authorization requires the user to manually agree, and since the user has agreed, there is no need to pay attention, and the user’s basic information can be obtained after authorization.
The “Interface for Obtaining User Basic Information” in the user management interface can obtain the user’s basic information based on the user’s OpenID only after the user interacts with the public account through messages or after the follow-up event is pushed. This interface, including other WeChat interfaces, requires the user (i.e. openid) to follow the official account before it can be called successfully.
Specifically, the web page authorization process is divided into four steps:
- Guide the user to enter the authorization page to agree to the authorization and obtain the code
- Exchange the code for web page authorization access_token (different from the access_token in basic support)
- If necessary, developers can refresh the web page authorization access_token to avoid expiration
- Obtain basic user information through web page authorization access_token and openid (supports UnionID mechanism)
The following is the encapsulated WeChat operation class. Two data tables are needed to save access_token and ticket. Since they have a certain validity period and the number of requests per day is capped, developers need to save them by themselves.
'The system is busy, developers please try again later', '0' => 'Request successful', '40001' => 'AppSecret is wrong or AppSecret does not belong to this official account, please developer confirm the correctness of AppSecret', '40002' => 'Please ensure that the grant\_type field value is client\_credential', '40164' => 'The IP address of the calling 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 page authorized login needs to be set in the official account - Function settings - Web page authorized domain name Step 1: User agrees to authorize and obtain code scope: snsapi\_base can only get openid and jump directly 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 page 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 necessary) Get openid through code $type 0 silent authorization 1 pop-up 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 is sick. It forces the file header to be displayed. $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 obtain 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; } } /\* Official Account Security Center Set IP Whitelist The public account's globally unique interface calling credentials. The public account needs to use access\_token when calling each interface. Developers need to store it properly. At least 512 characters of space must be reserved for access\_token storage. The validity period of access\_token is currently 2 hours and needs to be refreshed regularly. Repeated acquisition will cause the last 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; } } } // Obtaining js tickets needs to be set in the official 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 The URL of the current web page, excluding # and its following parts public function jsSign($data) { // 1. All parameters to be signed are sorted from small to large according to the ASCII code of the field name (lexicographic order) ksort($data); // 2. The format of the URL key-value pair (i.e. key1=value1&key2=value2...) is spliced into a string string1 using the original value without URL escaping. $string1 = $this->ToUrlParams($data); // echo "string1:{$string1}"; // 3. Perform sha1 encryption on string1 $sign = sha1($string1); // echo "signature:{$sign}
"; 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 to 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; }