提示:當你看到這個提示的時候,說明當前的文章是由原emlog博客系統搬遷至此的,文章發布時間已過於久遠,編排和內容不一定完整,還請諒解`
微信授權登錄
日期:2019-4-5 阿珏 折騰代碼 瀏覽:1874 次 評論:1 條
文檔: https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421135319微信的授權登錄和QQ、新浪等平台的授權登錄都大同小異,均採用 Oauth OAuth2.0鑑權方式。
微信授權分為兩種:
- 靜默授權
- 彈窗授權,需要用戶手動同意
兩種scope的區別說明
具體而言,網頁授權流程分為四步:
- 以snsapi_ base為scope發起的網頁授權,是用來獲取進入頁面的用戶的openid的,並且是靜默授權並自動跳轉到回調頁的。用戶感知的就是直接進入了回調頁(往往是業務頁面)
- 以snsapi_userinfo為scope發起的網頁授權,是用來獲取用戶的基本信息的。但這種授權需要用戶手動同意,並且由於用戶同意過,所以無須關注,就可在授權後獲取該用戶的基本信息。
具體而言,網頁授權流程分為四步:
- 引導用戶進入授權頁面同意授權,獲取code
- 通過code換取網頁授權access_token(與基礎支持中的access_token不同)
- 如果需要,開發者可以刷新網頁授權access_token,避免過期
- 通過網頁授權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)
文章不錯支持一下吧