1、在微信公眾號請求用戶網頁授權之前,開發者需要先到公眾平台官網中的“開發 - 接口權限 - 網頁服務 - 網頁帳號 - 網頁授權獲取用戶基本信息”的配置選項中,修改授權回調域名。請注意,這里填寫的是域名(是一個字符串),而不是URL,因此請勿加 http:// 等協議頭; 比如需要網頁授權的域名為:www.qq.com,配置以后此域名下面的頁面http://www.qq.com/music.html 、 http://www.qq.com/login.html 都可以進行OAuth2.0鑒權。但http://pay.qq.com 、 http://music.qq.com 、 http://qq.com無法進行OAuth2.0鑒權 (就是不能用)

2、關於網頁授權access_token和普通access_token的區別:我理解的就是 網頁授權的access_token沒什么特別的限制(雖然貌似也是2小時有效期)。大家隨便無限制用;但是除此之外用到的access_token是有限制的。真的是有效期2小時,而且每天有獲取access_token的限制次數。

因為有限制次數,所以我在做的時候是把獲取到的access_token保存在某個文件里,設置7000(小於一點點官方的2小時)秒過期,下次我再去獲取access_token的時候看這個設置的過期時間有沒有到。如果沒到。就直接獲取access_token值直接用。如果過期了,那么再次去獲取下。再次保存到這個文件里去;
另外普通過的access_token 是一個全局的共用的值,什么意思呢,比如你倆個模塊都用到了access_token 但是你 倆個模塊都單獨存了一份access_token的文件。那么恭喜你,你中招了。因為 每次用戶獲取一次access_token的時候微信的服務器是緩存記錄了最新access_token的最新值。比如你A模塊獲取更新了一次access_token,緊接着B模塊也獲取更新了一次access_token。那么,此時微信服務器緩存記錄的是B模塊獲取的access_token值,再接着A模塊去獲取一次access_token。因為是緊接着嘛,那么倆小時肯定沒到啊,也就是沒過期啊,那么自動從access_token保存文件里獲取值,可是實際此時微信服務器里緩存的access_token值 是B模塊最新更新的值啊,那你繼續進行你當前模塊下涉及到access_token的運算,肯定是要提示access_token錯誤的(跟服務器的不一致啊);
所以普通的access_token 一定要放在一個公共的,所有模塊都調用的同一個地方。這樣就避免了上面的錯誤;
好了,下面進入正題。先介紹下微信網頁授權的基本流程;
1.你進入到某個頁面,這個頁面先判斷地址url里有沒有code參數;如果有code參數直接調用請求以下鏈接獲取access_token: https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code 可以獲取到

直接就可以獲取到openid的值。 也就是完成了網頁授權的基本流程,剩下你自己程序的操作了。
2.如果這個頁面沒有code參數,那么先組裝url到那個讓用戶點擊授權的頁面,
https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect ;跳轉到這個url去,得到下圖

用戶點擊確認登錄之后。頁面自動貨跳轉到 redirect_uri/?code=CODE&state=STATE。這個頁面(redirect_uri是上面你自己設置url頁面,默認就是用戶剛開始進入第一個頁面的url)。
此時,等於又一次進入到當前頁面了。默認會執行第一步判斷操作(此時url獲取的code的值),完成授權基本流程。
getOpenId.php 代碼如下
<?php require_once "./lib/WxPay.JsApiPay.php"; $tools = new JsApiPay(); $openId = $tools->GetOpenid(); echo $openId; ?>
WxPay.Config.php代碼如下
<?php
/**
* 配置賬號信息
*/
class WxPayConfig
{
//=======【基本信息設置】=====================================
//
/**
* TODO: 修改這里配置為您自己申請的商戶信息
* 微信公眾號信息配置
*
* APPID:綁定支付的APPID(必須配置,開戶郵件中可查看)
*
* MCHID:商戶號(必須配置,開戶郵件中可查看)
*
* KEY:商戶支付密鑰,參考開戶郵件設置(必須配置,登錄商戶平台自行設置)
* 設置地址:https://pay.weixin.qq.com/index.php/account/api_cert
*
* APPSECRET:公眾帳號secert(僅JSAPI支付的時候需要配置, 登錄公眾平台,進入開發者中心可設置),
* 獲取地址:https://mp.weixin.qq.com/advanced/advanced?action=dev&t=advanced/dev&token=2005451881&lang=zh_CN
* @var string
*/
const APPID = '123123213213';
const MCHID = '123123123123123123';
const KEY = '13123123123213';
const APPSECRET = '123123213213213123213123';
//=======【證書路徑設置】=====================================
/**
* TODO:設置商戶證書路徑
* 證書路徑,注意應該填寫絕對路徑(僅退款、撤銷訂單時需要,可登錄商戶平台下載,
* API證書下載地址:https://pay.weixin.qq.com/index.php/account/api_cert,下載之前需要安裝商戶操作證書)
* @var path
*/
const SSLCERT_PATH = '../xxxx/apiclient_cert.pem';
const SSLKEY_PATH = '../xxxx/apiclient_key.pem';
//=======【curl代理設置】===================================
/**
* TODO:這里設置代理機器,只有需要代理的時候才設置,不需要代理,請設置為0.0.0.0和0
* 本例程通過curl使用HTTP POST方法,此處可修改代理服務器,
* 默認CURL_PROXY_HOST=0.0.0.0和CURL_PROXY_PORT=0,此時不開啟代理(如有需要才設置)
* @var unknown_type
*/
const CURL_PROXY_HOST = "0.0.0.0";//"10.152.18.220";
const CURL_PROXY_PORT = 0;//8080;
//=======【上報信息配置】===================================
/**
* TODO:接口調用上報等級,默認緊錯誤上報(注意:上報超時間為【1s】,上報無論成敗【永不拋出異常】,
* 不會影響接口調用流程),開啟上報之后,方便微信監控請求調用的質量,建議至少
* 開啟錯誤上報。
* 上報等級,0.關閉上報; 1.僅錯誤出錯上報; 2.全量上報
* @var int
*/
const REPORT_LEVENL = 1;
}
WxPay.JsApiPay.php代碼如下
<?php
require_once "WxPay.Config.php";
/**
*
* JSAPI支付實現類
* 該類實現了從微信公眾平台獲取code、通過code獲取openid和access_token、
* 生成jsapi支付js接口所需的參數、生成獲取共享收貨地址所需的參數
*
* 該類是微信支付提供的樣例程序,商戶可根據自己的需求修改,或者使用lib中的api自行開發
*
* @author widy
*
*/
class JsApiPay
{
/**
*
* 網頁授權接口微信服務器返回的數據,返回樣例如下
* {
* "access_token":"ACCESS_TOKEN",
* "expires_in":7200,
* "refresh_token":"REFRESH_TOKEN",
* "openid":"OPENID",
* "scope":"SCOPE",
* "unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"
* }
* 其中access_token可用於獲取共享收貨地址
* openid是微信支付jsapi支付接口必須的參數
* @var array
*/
public $data = null;
/**
*
* 通過跳轉獲取用戶的openid,跳轉流程如下:
* 1、設置自己需要調回的url及其其他參數,跳轉到微信服務器https://open.weixin.qq.com/connect/oauth2/authorize
* 2、微信服務處理完成之后會跳轉回用戶redirect_uri地址,此時會帶上一些參數,如:code
*
* @return 用戶的openid
*/
public function GetOpenid()
{
//通過code獲得openid
if (!isset($_GET['code'])){
//觸發微信返回code碼
$url = 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF'].$_SERVER['QUERY_STRING'];
$baseUrl = rtrim($url, '/');
$baseUrl = urlencode($baseUrl);
$url = $this->__CreateOauthUrlForCode($baseUrl);
Header("Location: $url");
exit();
} else {
//獲取code碼,以獲取openid
$code = $_GET['code'];
$openid = $this->getOpenidFromMp($code);
return $openid;
}
}
/**
*
* 獲取jsapi支付的參數
* @param array $UnifiedOrderResult 統一支付接口返回的數據
* @throws WxPayException
*
* @return json數據,可直接填入js函數作為參數
*/
public function GetJsApiParameters($UnifiedOrderResult)
{
if(!array_key_exists("appid", $UnifiedOrderResult)
|| !array_key_exists("prepay_id", $UnifiedOrderResult)
|| $UnifiedOrderResult['prepay_id'] == "")
{
throw new WxPayException("參數錯誤");
}
$jsapi = new WxPayJsApiPay();
$jsapi->SetAppid($UnifiedOrderResult["appid"]);
$timeStamp = time();
$jsapi->SetTimeStamp("$timeStamp");
$jsapi->SetNonceStr(WxPayApi::getNonceStr());
$jsapi->SetPackage("prepay_id=" . $UnifiedOrderResult['prepay_id']);
$jsapi->SetSignType("MD5");
$jsapi->SetPaySign($jsapi->MakeSign());
$parameters = json_encode($jsapi->GetValues());
return $parameters;
}
/**
*
* 通過code從工作平台獲取openid機器access_token
* @param string $code 微信跳轉回來帶上的code
*
* @return openid
*/
public function GetOpenidFromMp($code)
{
$url = $this->__CreateOauthUrlForOpenid($code);
//初始化curl
$ch = curl_init();
//設置超時
// curl_setopt($ch, CURLOPT_TIMEOUT, $this->curl_timeout);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER,FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST,FALSE);
curl_setopt($ch, CURLOPT_HEADER, FALSE);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
if(WxPayConfig::CURL_PROXY_HOST != "0.0.0.0"
&& WxPayConfig::CURL_PROXY_PORT != 0){
curl_setopt($ch,CURLOPT_PROXY, WxPayConfig::CURL_PROXY_HOST);
curl_setopt($ch,CURLOPT_PROXYPORT, WxPayConfig::CURL_PROXY_PORT);
}
//運行curl,結果以jason形式返回
$res = curl_exec($ch);
curl_close($ch);
//取出openid
$data = json_decode($res,true);
$this->data = $data;
$openid = $data['openid'];
return $openid;
}
/**
*
* 拼接簽名字符串
* @param array $urlObj
*
* @return 返回已經拼接好的字符串
*/
private function ToUrlParams($urlObj)
{
$buff = "";
foreach ($urlObj as $k => $v)
{
if($k != "sign"){
$buff .= $k . "=" . $v . "&";
}
}
$buff = trim($buff, "&");
return $buff;
}
/**
*
* 獲取地址js參數
*
* @return 獲取共享收貨地址js函數需要的參數,json格式可以直接做參數使用
*/
public function GetEditAddressParameters()
{
$getData = $this->data;
$data = array();
$data["appid"] = WxPayConfig::APPID;
$data["url"] = "http://".$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
$time = time();
$data["timestamp"] = "$time";
$data["noncestr"] = "1234568";
$data["accesstoken"] = $getData["access_token"];
ksort($data);
$params = $this->ToUrlParams($data);
$addrSign = sha1($params);
$afterData = array(
"addrSign" => $addrSign,
"signType" => "sha1",
"scope" => "jsapi_address",
"appId" => WxPayConfig::APPID,
"timeStamp" => $data["timestamp"],
"nonceStr" => $data["noncestr"]
);
$parameters = json_encode($afterData);
return $parameters;
}
/**
*
* 構造獲取code的url連接
* @param string $redirectUrl 微信服務器回跳的url,需要url編碼
*
* @return 返回構造好的url
*/
private function __CreateOauthUrlForCode($redirectUrl)
{
$urlObj["appid"] = WxPayConfig::APPID;
$urlObj["redirect_uri"] = "$redirectUrl";
$urlObj["response_type"] = "code";
$urlObj["scope"] = "snsapi_base";
$urlObj["state"] = "STATE"."#wechat_redirect";
$bizString = $this->ToUrlParams($urlObj);
return "https://open.weixin.qq.com/connect/oauth2/authorize?".$bizString;
}
/**
*
* 構造獲取open和access_toke的url地址
* @param string $code,微信跳轉帶回的code
*
* @return 請求的url
*/
private function __CreateOauthUrlForOpenid($code)
{
$urlObj["appid"] = WxPayConfig::APPID;
$urlObj["secret"] = WxPayConfig::APPSECRET;
$urlObj["code"] = $code;
$urlObj["grant_type"] = "authorization_code";
$bizString = $this->ToUrlParams($urlObj);
return "https://api.weixin.qq.com/sns/oauth2/access_token?".$bizString;
}
}
注意code只能用一次的。如果你第一次頁面獲取到openid了,你刷新這個頁面。就會報錯。
