github
手把手實(shí)現(xiàn)微信網(wǎng)頁(yè)授權(quán)和微信支付,附源代碼(VUE and thinkPHP)
概述
公眾號(hào)開(kāi)發(fā)是痛苦的,痛苦在好多問(wèn)題開(kāi)發(fā)者文檔是沒(méi)有提到的,是需要你猜的. 在開(kāi)發(fā)過(guò)程中翻了好多的文檔,都是說(shuō)明其中的一部分問(wèn)題的,很費(fèi)時(shí)間,所以在此總結(jié)大體過(guò)程。我們模擬的是一個(gè)支付的商城,在實(shí)現(xiàn)購(gòu)買(mǎi)過(guò)程中基本是把微信公眾號(hào)最主要模塊實(shí)現(xiàn)了,其余的功能我們沒(méi)有涉及,但應(yīng)該是觸類(lèi)旁通的。
我們敘述的過(guò)程是按開(kāi)發(fā)流程進(jìn)行敘述的,不會(huì)是按照開(kāi)發(fā)文檔的形式敘述,希望您能結(jié)合微信的開(kāi)發(fā)文檔一起閱讀,當(dāng)然在流程中我們會(huì)提醒你閱讀的部分
目錄
-
概述
- [解決的問(wèn)題]
- [前端技術(shù)棧]
- [后端技術(shù)棧]
- [基本說(shuō)明]
- [開(kāi)發(fā)過(guò)程]
- [0.準(zhǔn)備]
- [1.基本配置]
- [2.網(wǎng)頁(yè)授權(quán)]
-
JS-SDK
- [簽名]
- [簽名后臺(tái)]
- [簽名前臺(tái)]
- [微信支付]
解決的問(wèn)題
- [x] 微信網(wǎng)頁(yè)授權(quán)
- [x] 公眾號(hào)支付
- [x] 公眾號(hào)分享
- [x] 公眾號(hào)掃一掃
- [x] 微信后臺(tái)獲取webapp(spa-vue)路由,導(dǎo)致 invalid 問(wèn)題
- [x] 前端history.pushState()導(dǎo)致ios失效問(wèn)題
- [x] 換取微信openID 順序問(wèn)題
- [x] 網(wǎng)頁(yè)授權(quán)后強(qiáng)制登錄官網(wǎng)賬戶(hù),全局進(jìn)行攔截
前端技術(shù)棧
vue2 + vuex + vue-router + webpack + ES6/7 + axios + sass + flex
后端技術(shù)棧
thinkPHP3.2 + mysql + 阿里云Linux Ubuntu
基本說(shuō)明
開(kāi)發(fā)環(huán)境 macOS 10.13.3 nodejs 8.0.0 centOS 7.4
本文中使用的url是m.example.com (demo), 開(kāi)發(fā)過(guò)程中需要替換成你的URL。
如有問(wèn)題請(qǐng)直接在 Issues 中提,或者您發(fā)現(xiàn)問(wèn)題并有非常好的解決方案,歡迎 PR
本著
線上線下一樣的原則,最好申請(qǐng)兩個(gè)認(rèn)證微信公眾號(hào),一個(gè)是發(fā)布使用,一個(gè)是本地開(kāi)發(fā)使用。微信自帶提供的微信測(cè)試功能也不太好用
可以添加群交流 544958637
開(kāi)發(fā)過(guò)程
0.準(zhǔn)備
請(qǐng)閱讀以下微信開(kāi)發(fā)者文檔
附:參數(shù)說(shuō)明
appid:公眾號(hào)唯一標(biāo)識(shí)id(公眾號(hào)-開(kāi)發(fā)-基本配置中查看)。
secret:公眾號(hào)開(kāi)發(fā)密鑰(初次請(qǐng)保存本地,忘記請(qǐng)重置)。
openid: 每個(gè)微信用戶(hù)關(guān)注此公眾號(hào)后會(huì)生成openid,并且在此公眾號(hào)中每個(gè)用戶(hù)得openid是唯一的。
code : code作為換取access_token的票據(jù),每次用戶(hù)授權(quán)帶上的code將不一樣,code只能使用一次,5分鐘未被使用自動(dòng)過(guò)期。
IP 白名單:允許訪問(wèn)微信服務(wù)器的ip(linux 公網(wǎng)ip 注意如果服務(wù)器有CDN加速,CDN請(qǐng)?zhí)砑影酌麊危?/p>
1.基本配置
-
基礎(chǔ)工具
- 一個(gè)已經(jīng)認(rèn)證的公眾號(hào)(就是你已經(jīng)交300元)
- 已經(jīng)備案的域名
- 域名解析到服務(wù)器 傳送門(mén)node項(xiàng)目發(fā)布+域名及其二級(jí)域名配置+nginx反向代理+pm2
- 微信開(kāi)發(fā)者工具下載 : 微信開(kāi)發(fā)可定使用這個(gè)工具。必須把前端代碼放到》服務(wù)器上》用這個(gè)工具調(diào)試。請(qǐng)仔細(xì)閱讀微信web開(kāi)發(fā)者工具 使用指南
-
設(shè)置
web開(kāi)發(fā)者工具在
開(kāi)發(fā)-開(kāi)發(fā)者工具-web開(kāi)發(fā)者工具設(shè)置開(kāi)發(fā)者賬號(hào) -
設(shè)置IP 白名單
在
設(shè)置-安全中心-IP白名單設(shè)置你服務(wù)器的IP,通過(guò)開(kāi)發(fā)者ID及密碼調(diào)用獲取access_token接口時(shí),需要設(shè)置訪問(wèn)來(lái)源IP為白名單。 -
設(shè)置基本配置-開(kāi)發(fā)者ID
設(shè)置開(kāi)發(fā)者密碼(AppSecret)
image我們獲取到的AppSecret (eg) a66b789009df271cde47aaaaaaa
-
設(shè)置服務(wù)器基本配置
這部的目的是為了和微信服務(wù)器建立聯(lián)系, 通過(guò)微信平臺(tái)實(shí)現(xiàn)我們的業(yè)務(wù)邏輯。

詳細(xì)版:

接入微信公眾平臺(tái)開(kāi)發(fā),開(kāi)發(fā)者需要按照如下步驟完成:
1、填寫(xiě)服務(wù)器配置
2、驗(yàn)證服務(wù)器地址的有效性
3、依據(jù)接口文檔實(shí)現(xiàn)業(yè)務(wù)邏輯
下面詳細(xì)介紹這3個(gè)步驟。
**第一步:填寫(xiě)服務(wù)器配置**
* 登錄微信公眾平臺(tái)官網(wǎng)后,在公眾平臺(tái)官網(wǎng)的開(kāi)發(fā)-基本設(shè)置頁(yè)面,勾選協(xié)議成為開(kāi)發(fā)者,點(diǎn)擊“修改配置”按鈕、。
* 填寫(xiě)服務(wù)器地址(URL)、Token和EncodingAESKey
* URL是開(kāi)發(fā)者用來(lái)接收微信消息和事件的接口URL。
* Token可由開(kāi)發(fā)者可以任意填寫(xiě),用作生成簽名(該Token會(huì)和接口URL中包含的Token進(jìn)行比對(duì),從而驗(yàn)證安全性)
* EncodingAESKey由開(kāi)發(fā)者手動(dòng)填寫(xiě)或隨機(jī)生成,將用作消息體加解密密鑰。
* 同時(shí),開(kāi)發(fā)者可選擇消息加解密方式:明文模式、兼容模式和安全模式。模式的選擇與服務(wù)器配置在提交后都會(huì)立即生效
* 加解密方式的默認(rèn)狀態(tài)為明文模式,選擇兼容模式和安全模式需要提前配置好相關(guān)加解密代碼

第二步:驗(yàn)證消息的確來(lái)自微信服務(wù)器
?
現(xiàn)在如果你點(diǎn)擊確認(rèn) 按鈕,肯定會(huì)報(bào)認(rèn)證錯(cuò)誤。因?yàn)槲覀儧](méi)有做微信認(rèn)證請(qǐng)求 接收。 開(kāi)發(fā)者提交信息后,微信服務(wù)器將發(fā)送GET請(qǐng)求到填寫(xiě)的服務(wù)器地址URL上,GET請(qǐng)求攜帶參數(shù)如下表所示:
?
| 參數(shù) | 描述 |
|---|---|
| signature | 微信加密簽名,signature結(jié)合了開(kāi)發(fā)者填寫(xiě)的token參數(shù)和請(qǐng)求中的timestamp參數(shù)、nonce參數(shù)。 |
| timestamp | 時(shí)間戳 |
| nonce | 隨機(jī)數(shù) |
| echostr | 隨機(jī)字符串 |
開(kāi)發(fā)者通過(guò)檢驗(yàn)signature對(duì)請(qǐng)求進(jìn)行校驗(yàn)(下面有校驗(yàn)方式)。若確認(rèn)此次GET請(qǐng)求來(lái)自微信服務(wù)器,請(qǐng)?jiān)瓨臃祷豦chostr參數(shù)內(nèi)容,則接入生效,成為開(kāi)發(fā)者成功,否則接入失敗。加密/校驗(yàn)流程如下:
- 將token、timestamp、nonce三個(gè)參數(shù)進(jìn)行字典序排序
- 將三個(gè)參數(shù)字符串拼接成一個(gè)字符串進(jìn)行sha1加密
- 開(kāi)發(fā)者獲得加密后的字符串可與signature對(duì)比,標(biāo)識(shí)該請(qǐng)求來(lái)源于微信
微信官方提供在文檔中提供了PHP原生示例 PHP原生驗(yàn)證demo
Thinkphp 3.2 驗(yàn)證示例
<?php
namespace Home\Controller;//命名空間注意用自己的
use Think\Controller; //引入Think Controller
/**
* Class IndexController
* @package Home\Controller
* @name 微信服務(wù)器驗(yàn)證類(lèi)
* @author weikai
*/
class IndexController extends Controller {
//微信服務(wù)器接入
public function index()
{
//這個(gè)echostr呢 只有說(shuō)驗(yàn)證的時(shí)候才會(huì)echo 如果是驗(yàn)證過(guò)之后這個(gè)echostr是不存在的字段了
if($_GET['echostr']){
$echoStr = $_GET["echostr"];
if ($this->checkSignature()) {
ob_clean();//防止之前緩存區(qū)數(shù)據(jù)影響
echo $echoStr;
exit;
}
}else{
$this->responseMsg(); //如果沒(méi)有echostr,則返回消息
}
}
//驗(yàn)證微信開(kāi)發(fā)者模式接入是否成功
private function checkSignature()
{
//signature 是微信傳過(guò)來(lái)的簽名
$signature = $_GET["signature"];
//微信發(fā)過(guò)來(lái)的時(shí)間戳
$timestamp = $_GET["timestamp"];
//微信傳過(guò)來(lái)的值隨機(jī)字符串
$nonce = $_GET["nonce"];
//定義你在微信公眾號(hào)開(kāi)發(fā)者模式里面定義的token 這里舉例為weixin
$token = "weixin";
//三個(gè)變量 按照字典排序 形成一個(gè)數(shù)組
$tmpArr = array(
$token,
$timestamp,
$nonce
);
// 字典排序
sort($tmpArr, SORT_STRING);
$tmpStr = implode($tmpArr);
//哈希加密 在laravel里面是Hash::
$tmpStr = sha1($tmpStr);
//哈希加密后的數(shù)據(jù) 和微信服務(wù)器傳過(guò)來(lái)的簽名比較
if ($tmpStr == $signature) {
return true;
} else {
return false;
}
}
/**
* @name 消息接收
* @author weikai
*/
public function responseMsg()//執(zhí)行接收器方法
{
//獲取微信服務(wù)器的XML數(shù)據(jù) 轉(zhuǎn)化為對(duì)象 判斷消息類(lèi)型
$postStr = $GLOBALS["HTTP_RAW_POST_DATA"];
if (!empty($postStr)){
$postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
$RX_TYPE = trim($postObj->MsgType);
switch($RX_TYPE){
case "event":
$result = $this->receiveEvent($postObj);
break;
case "text":
$result = $this->handleText($postObj);
break;
}
echo $result;
}else{
echo "";
exit;
}
}
} //classend
**注意:示例代碼中 Token 要與微信公眾號(hào)基本配置中的Token 一致 **
微信公眾號(hào)基本配置中點(diǎn)擊啟用配置,如果驗(yàn)證失敗可能是網(wǎng)絡(luò)延遲導(dǎo)致,再點(diǎn)擊啟用多試幾次,3次以上不成功,請(qǐng)檢查代碼。
2.網(wǎng)頁(yè)授權(quán)
如果使用支付功能,必須先授權(quán)
大家應(yīng)該經(jīng)歷過(guò),我們?cè)诠娞?hào)打開(kāi)頁(yè)面,一般都會(huì)彈出一個(gè)按鈕需要我們點(diǎn)擊同意才會(huì)繼續(xù)瀏覽頁(yè)面

但是我們第二次點(diǎn)擊的時(shí)候是不需要點(diǎn)擊授權(quán)的,這兩個(gè)過(guò)程是不同的,是兩種授權(quán):(樣例不可直接使用,是demo)
- 非靜默授權(quán)的 URL 樣例:(scope=snsapi_userinfo)
請(qǐng)注意加粗部分
https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx841a97238d9e17b2&redirect_uri=http://cps.dianping.com/weiXinRedirect&response_type=code&scope=snsapi_userinfo&state=type%3Dquan%2Curl%3Dhttp%3A%2F%2Fmm.dianping.com%2Fweixin%2Faccount%2Fhome
點(diǎn)擊`允許`即可帶著用戶(hù)信息跳轉(zhuǎn)到第三方頁(yè)面,如上圖.
作用: 是用來(lái)獲取用戶(hù)的基本信息的
- 靜默授權(quán)的 URL 樣例: (scope=snsapi_base)
請(qǐng)注意加粗部分
https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx841a97238d9e17b2&redirect_uri=http://cps.dianping.com/weiXinRedirect&response_type=code&scope=snsapi_base&state=type%3Dquan%2Curl%3Dhttp%3A%2F%2Fmm.dianping.com%2Fweixin%2Faccount%2Fhome
在微信 web 開(kāi)發(fā)者工具中打開(kāi)類(lèi)似的授權(quán)頁(yè) URL 則會(huì)`自動(dòng)跳轉(zhuǎn)`到第三方頁(yè)面。
作用:是用來(lái)獲取進(jìn)入頁(yè)面的用戶(hù)的openid的
注意:倆者授權(quán)區(qū)別
非靜默授權(quán):可獲取微信用戶(hù)基礎(chǔ)信息如 用戶(hù)微信昵稱(chēng) 、城市、語(yǔ)言、頭像、關(guān)注公眾號(hào)時(shí)間、openid等。
靜默授權(quán):用戶(hù)體驗(yàn)好,用戶(hù)不知覺(jué)間完成授權(quán),但只可以獲取到用戶(hù)得openid。
網(wǎng)頁(yè)授權(quán)
請(qǐng)通讀微信網(wǎng)頁(yè)授權(quán)
請(qǐng)注意 關(guān)于網(wǎng)頁(yè)授權(quán)access_token和普通access_token的區(qū)別 章節(jié)
具體而言,網(wǎng)頁(yè)授權(quán)流程分為四步:
注意: 步驟一是由前臺(tái)完成的,前臺(tái)獲取code 之后需要傳給后臺(tái),由后臺(tái)完成 2 3 4
1. 引導(dǎo)用戶(hù)進(jìn)入授權(quán)頁(yè)面同意授權(quán)后微信跳轉(zhuǎn)回調(diào)地址并傳遞參數(shù)code 獲取code
2. 通過(guò)code換取網(wǎng)頁(yè)授權(quán)access_token(與基礎(chǔ)支持中的access_token不同)
3. 如果需要,開(kāi)發(fā)者可以刷新網(wǎng)頁(yè)授權(quán)access_token,避免過(guò)期
4. 通過(guò)網(wǎng)頁(yè)授權(quán)access_token和openid獲取用戶(hù)基本信息(支持UnionID機(jī)制)

1、引導(dǎo)用戶(hù)進(jìn)入授權(quán)頁(yè)面同意授權(quán),獲取code
建議:如果路由由vue管理,建議code由前臺(tái)獲取并發(fā)送給后臺(tái)。 在公眾賬號(hào)中配置授權(quán)回調(diào)域名

(${redirect_url}看下面)
微信授權(quán)是前端發(fā)起的,
時(shí)機(jī): 是在你需要獲取微信信息之前的頁(yè)面發(fā)起請(qǐng)求,當(dāng)然大部分情況是用戶(hù)進(jìn)入webapp 我們就開(kāi)始授權(quán),我們的dome中就是進(jìn)入立馬授權(quán)
前臺(tái)(Vue): 前臺(tái)做引導(dǎo)到授權(quán)頁(yè)面,使用location.href 就可以實(shí)現(xiàn)。授權(quán)過(guò)程中會(huì)有幾次這頁(yè)面跳轉(zhuǎn)。我們把授權(quán)函數(shù)放在
router.beforeEach((to, from, next)=> {})函數(shù)中,好控制。跳轉(zhuǎn): 我們剛才提到前臺(tái)需要引導(dǎo),這個(gè)引導(dǎo)路徑是需要后臺(tái)提供,基本的形式是
location.href = http://m.example.com/Home/WxSignature/getBaseInfos?redirect_url=${redirect_url}。要注意redirect_url=${redirect_url},${redirect_url}是告訴后臺(tái)回調(diào)到前臺(tái)的URL(請(qǐng)encodeURIComponent).
-
后臺(tái)(PHP): 前臺(tái)調(diào)到了后臺(tái),后臺(tái)此時(shí)需要獲取code了。后臺(tái)要通過(guò) 特定的URL(見(jiàn)官網(wǎng)
第一步:用戶(hù)同意授權(quán),獲取code)獲取code.api參數(shù)解釋?zhuān)?/strong>
appid : 請(qǐng)查看本文 參數(shù)說(shuō)明
redirect_uri : 回調(diào)鏈接,完成用戶(hù)授權(quán)后微信服務(wù)器自動(dòng)回調(diào)得uri,一般為業(yè)務(wù)首頁(yè)鏈接(注意請(qǐng)轉(zhuǎn)義)。
response_type : 固定為code 。
scope : 授權(quán)方式 可選靜默(snsapi_base) 或者非靜默(snsapi_userinfo)
state : 此參數(shù)可為業(yè)務(wù)需求使用,根據(jù)業(yè)務(wù)需要傳入。
靜默授權(quán)方式獲取code:
https://open.weixin.qq.com/connect/oauth2/authorize?appid=你的appid&redirect_uri=https%3A%2F%2Fchong.qq.com%2Fphp%2Findex.php%3Fd%3D%26c%3DwxAdapter%26m%3DmobileDeal%26showwxpaytitle%3D1%26vb2ctag%3D4_2030_5_1194_60&response_type=code&scope=snsapi_base&state=123#wechat_redirect非靜默授權(quán)方式獲取code:
https://open.weixin.qq.com/connect/oauth2/authorize?appid=wxf0e81c3bee622d60&redirect_uri=http%3A%2F%2Fnba.bluewebgame.com%2Foauth_response.php&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect
/**
* @name 授權(quán)引導(dǎo)后微信會(huì)跳轉(zhuǎn)到回調(diào)地址并攜帶code參數(shù)
* @author weikai
*/
public function getBaseInfos(){
$redirect_url = I('get.redirect_url');//獲取前臺(tái)傳遞的回調(diào)地址
$app_id = C('WX_APPID');//獲取自己公眾號(hào)的 appid
$redirect_uri = urlencode($redirect_url);//處理url
$url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=".$app_id."&redirect_uri=".$redirect_uri."&response_type=code&scope=snsapi_userinfo&state=1#wechat_redirect";
header('location:'.$url);
}
錯(cuò)誤返回碼說(shuō)明如下:
| 返回碼 | 說(shuō)明 |
|---|---|
| 10003 | redirect_uri域名與后臺(tái)配置不一致 |
| 10004 | 此公眾號(hào)被封禁 |
| 10005 | 此公眾號(hào)并沒(méi)有這些scope的權(quán)限 |
| 10006 | 必須關(guān)注此測(cè)試號(hào) |
| 10009 | 操作太頻繁了,請(qǐng)稍后重試 |
| 10010 | scope不能為空 |
| 10011 | redirect_uri不能為空 |
| 10012 | appid不能為空 |
| 10013 | state不能為空 |
| 10015 | 公眾號(hào)未授權(quán)第三方平臺(tái),請(qǐng)檢查授權(quán)狀態(tài) |
| 10016 | 不支持微信開(kāi)放平臺(tái)的Appid,請(qǐng)使用公眾號(hào)Appid |
-
前臺(tái)獲取code
引導(dǎo)用戶(hù)到授權(quán)頁(yè)面后 微信服務(wù)器會(huì)根據(jù)redirect_uri參數(shù)跳轉(zhuǎn),并且攜帶code參數(shù)和值

前臺(tái)截取出code 就可以了,傳給后臺(tái),到這里基本就可以了。但是我們通常是用戶(hù)每次登陸都需要進(jìn)行授權(quán),我們判斷url中的參數(shù)就可以實(shí)現(xiàn)了。往往我們也要監(jiān)聽(tīng)用戶(hù)是否登錄,判斷用戶(hù)是否需要賬號(hào)密碼登錄也需要在 router.beforeEach((to, from, next)=> {}) 實(shí)現(xiàn),beforeEach()有些復(fù)雜了,請(qǐng)大家閱讀具體代碼。請(qǐng)結(jié)合自己具體的業(yè)務(wù)書(shū)寫(xiě)
/**
* 判斷用戶(hù)是否需要賬號(hào)密碼登錄,login頁(yè)面監(jiān)聽(tīng)
* @Author Hybrid
* @DateTime 2018-02-28
*/
let checkIsLoginGotologin = function(to, next) {
// isRelation 判斷用戶(hù)微信賬戶(hù)是否關(guān)聯(lián)官網(wǎng)賬戶(hù)
// routeArr 是一些路由是不需要受監(jiān)聽(tīng)的
// !res ? 已經(jīng)授權(quán) :沒(méi)有授權(quán)
isRelation().then(res => {
if (routeArr.includes(to.path)) {
!res ? next('index') : next();
} else {
// 沒(méi)有授權(quán)且不是授權(quán)頁(yè) // 當(dāng)在授權(quán)的情況下是不允許訪問(wèn)login頁(yè)面
(res && to.path !== '/login') ? next('/login'): ((!res && to.path === '/login') ? next('index') : next())
}
})
}
/**
* 獲取和推送code
* @Author Hybrid
* @DateTime 2018-02-28
* @param {} url 路徑
*/
let getCodePullCode = async function(url) {
let mycode = url.substring(url.indexOf('code=') + 5, url.indexOf('state=') - 1);// 前臺(tái)截取code
selfStore.set('wechatCodeStr', mycode); // 存儲(chǔ)code
//傳送給后臺(tái)code
await axios
.get("/home/WxSignature/getCode", {
params: {
code: mycode
}
})
.then(res => {
//需要登錄
var res = res.data;
if (res && res.status === 1) {
selfStore.set('openId', res.data);//本地存儲(chǔ)Openid,也可以不存儲(chǔ)。由后臺(tái)調(diào)配
location.href = `http://m.example.com/?a=1#${location.href.split('#')[1]}`; // 增加a=1 防止支付錯(cuò)誤 防止前臺(tái)死循環(huán)
}
});
}
/**
* 全局路由
* @Author Hybrid
* @DateTime 2018-02-28
*/
if (process.env.NODE_ENV == 'production') {
router.beforeEach((to, from, next) => {
let url = location.href;
// 同時(shí)判斷'a=1' 和code= 防止前臺(tái)死循環(huán)
// wechatCode沒(méi)有 發(fā)起授權(quán)
if ((url.indexOf('a=1') < 1) && (url.indexOf('code=') < 1)) {
let redirect_url = encodeURIComponent(`http://m.example.com#${to.path}`);
location.href = `http://m.example.com/Home/WxSignature/getBaseInfos?redirect_url=${redirect_url}`;
} else {
// 后臺(tái)重定向頁(yè)面,授權(quán)登錄
(!(url.indexOf('code=') < 1)) ? getCodePullCode(url): checkIsLoginGotologin(to, next)
}
})
}
2、通過(guò)code換取網(wǎng)頁(yè)授權(quán)access_token(與基礎(chǔ)支持中的access_token不同)
appid : 請(qǐng)查看本文 參數(shù)說(shuō)明
secret : 請(qǐng)查看本文 參數(shù)說(shuō)明
code :獲取到得code。
grant_type : 固定為authorization_code
獲取code后,請(qǐng)求以下鏈接獲取access_token以及用戶(hù)得openid:
https://api.weixin.qq.com/sns/oauth2/access_token?appid=你的appid&secret=你的sercret&code=剛剛獲取得code&grant_type=authorization_code
/**
* 前臺(tái)傳遞code,后臺(tái)存儲(chǔ)
* @Author weikai
* @DateTime 2017-11-23
* @return [type] [description]
*/
public function getCode() {
$code = I('get.code');//授權(quán)用code
$appid = C('WX_APPID');//你的公眾號(hào)appid
$secret = C('WX_APPSECRET');//你的公眾號(hào)secret
// 組合獲取的url
$url="https://api.weixin.qq.com/sns/oauth2/access_token? appid=$appid&secret=$secret&code=$code&grant_type=authorization_code";
// curl獲取access_token 和openid
$result=$this->curl_get_contents($url);//curl get請(qǐng)求函數(shù)請(qǐng)自行百度
$result=json_decode($result,true);//json轉(zhuǎn)數(shù)組
$data['openid']=$result['openid'];
$data['access_token'] = $result['access_token'];
$data['refresh_token'] = $result['refresh_token'];
if($data){
return $this->ajaxReturn(show(1,'獲取access_token 和openid',$data));//show()方法為自定義封裝消息
}else{
return $this->ajaxReturn(show(0,'沒(méi)有access_token 和openid'));
}
}
正確時(shí)返回的JSON數(shù)據(jù)包如下:
{ "access_token":"ACCESS_TOKEN",
"expires_in":7200,
"refresh_token":"REFRESH_TOKEN",
"openid":"OPENID",
"scope":"SCOPE" }
有些數(shù)據(jù)是需要存儲(chǔ)到后臺(tái)數(shù)據(jù)庫(kù)的如openid
| 參數(shù) | 描述 |
|---|---|
| access_token | 網(wǎng)頁(yè)授權(quán)接口調(diào)用憑證,注意:此access_token與基礎(chǔ)支持的access_token不同 |
| expires_in | access_token接口調(diào)用憑證超時(shí)時(shí)間,單位(秒) |
| refresh_token | 用戶(hù)刷新access_token |
| openid | 用戶(hù)唯一標(biāo)識(shí),請(qǐng)注意,在未關(guān)注公眾號(hào)時(shí),用戶(hù)訪問(wèn)公眾號(hào)的網(wǎng)頁(yè),也會(huì)產(chǎn)生一個(gè)用戶(hù)和公眾號(hào)唯一的OpenID |
| scope | 用戶(hù)授權(quán)的作用域,使用逗號(hào)(,)分隔 |
錯(cuò)誤時(shí)微信會(huì)返回JSON數(shù)據(jù)包如下(示例為Code無(wú)效錯(cuò)誤):
{"errcode":40029,"errmsg":"invalid code"}
其實(shí)完成第二步就完成了基本的網(wǎng)頁(yè)授權(quán)但是還沒(méi)有獲取到用戶(hù)的信息,授權(quán)也沒(méi)有實(shí)際作用了。
3、刷新access_token(如果需要)
由于獲取用戶(hù)信息所用得access_token有效時(shí)常比較短,如果想獲取access_token后間隔時(shí)間較長(zhǎng)獲取微信用戶(hù)基本信息請(qǐng)請(qǐng)求刷新access_token api
我這里沒(méi)有采用授權(quán)后拉取用戶(hù)信息的api,而是采用用戶(hù)信息獲取的api。
請(qǐng)求方法
獲取第二步的refresh_token后,請(qǐng)求以下鏈接獲取access_token:
https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=APPID&grant_type=refresh_token&refresh_token=REFRESH_TOKEN
| 參數(shù) | 是否必須 | 說(shuō)明 |
|---|---|---|
| appid | 是 | 公眾號(hào)的唯一標(biāo)識(shí) |
| grant_type | 是 | 填寫(xiě)為refresh_token |
| refresh_token | 是 | 填寫(xiě)通過(guò)access_token獲取到的refresh_token參數(shù) |
/**
* 刷新access_token
* @Author weikai
* @refresh_token 用與刷新access_token的參數(shù)
* @DateTime 2017-11-23
* @return [type] [description]
*/
public function reAccessToken($refresh_token) {
$appid = C('WX_APPID');//你的公眾號(hào)appid
// 組合獲取的url
$url="https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=$appid&grant_type=refresh_token&refresh_token=$refresh_token";
// curl請(qǐng)求刷新access_token
$result=$this->curl_get_contents($url);//curl get請(qǐng)求函數(shù)請(qǐng)自行百度
$result=json_decode($result,true);//json轉(zhuǎn)數(shù)組
$data['access_token'] = $result['access_token'];
if($data){
return $this->ajaxReturn(show(1,'獲取access_token' ,$data));//show()方法為自定義封裝消息
}else{
return $this->ajaxReturn(show(0,'沒(méi)有access_token'));
}
}
返回說(shuō)明
正確時(shí)返回的JSON數(shù)據(jù)包如下:
{ "access_token":"ACCESS_TOKEN",
"expires_in":7200,
"refresh_token":"REFRESH_TOKEN",
"openid":"OPENID",
"scope":"SCOPE" }
和上步返回的數(shù)據(jù)相同,目的就是刷新了access_token 的有效時(shí)間,有效期內(nèi)可以使用access_token 和openid獲取微信用戶(hù)信息
4、通過(guò)網(wǎng)頁(yè)授權(quán)access_token和openid獲取用戶(hù)基本信息
注意:
這里微信提供了兩個(gè)不同的api
1.在微信授權(quán)里微信提供拉取用戶(hù)信息的api(access_token時(shí)間限制為五分鐘失效)
http:GET
https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN
參數(shù)說(shuō)明
| 參數(shù) | 描述 |
|---|---|
| access_token | 網(wǎng)頁(yè)授權(quán)接口調(diào)用憑證,注意:此access_token與基礎(chǔ)支持的access_token不同 |
| openid | 用戶(hù)的唯一標(biāo)識(shí) |
| lang | 返回國(guó)家地區(qū)語(yǔ)言版本,zh_CN 簡(jiǎn)體,zh_TW 繁體,en 英語(yǔ) |
2.微信用戶(hù)管理提供的獲取用戶(hù)信息api(只需要使用全局access_token有效期2小時(shí),和openid)
推薦使用這個(gè)接口獲取用戶(hù)信息
http: GET
https://api.weixin.qq.com/cgi-bin/user/info?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN
參數(shù)說(shuō)明
| 參數(shù) | 描述 |
|---|---|
| access_token | 全局access_token 有效期7200秒 |
| openid | 用戶(hù)的唯一標(biāo)識(shí) |
| lang | 返回國(guó)家地區(qū)語(yǔ)言版本,zh_CN 簡(jiǎn)體,zh_TW 繁體,en 英語(yǔ) |
如果網(wǎng)頁(yè)授權(quán)參數(shù)為snsapi_userinfo(非靜默授權(quán)),則此時(shí)可以通過(guò)access_token和openid獲取用戶(hù)信息了。
PHP示例
/**
* @return mixed
* @name 使用全局access_token獲取用戶(hù)詳細(xì)信息
* @author weikai
*/
public function getWxUserInfo($openid){
$access_token = $this->getAccess_Token();
$url = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=".$access_token."&openid=".$openid."&lang=zh_CN";
$data = $this->cUrl($url);
$data = json_decode($data);
if($data){
return $data;
}
}
返回說(shuō)明
正確時(shí)返回的JSON數(shù)據(jù)包如下:
{ "openid":" OPENID",
" nickname": NICKNAME,
"sex":"1",
"province":"PROVINCE"
"city":"CITY",
"country":"COUNTRY",
"headimgurl": "http://thirdwx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/46",
"privilege":[ "PRIVILEGE1" "PRIVILEGE2" ],
"unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"
}
| 參數(shù) | 描述 |
|---|---|
| openid | 用戶(hù)的唯一標(biāo)識(shí) |
| nickname | 用戶(hù)昵稱(chēng) |
| sex | 用戶(hù)的性別,值為1時(shí)是男性,值為2時(shí)是女性,值為0時(shí)是未知 |
| province | 用戶(hù)個(gè)人資料填寫(xiě)的省份 |
| city | 普通用戶(hù)個(gè)人資料填寫(xiě)的城市 |
| country | 國(guó)家,如中國(guó)為CN |
| headimgurl | 用戶(hù)頭像,最后一個(gè)數(shù)值代表正方形頭像大小(有0、46、64、96、132數(shù)值可選,0代表640*640正方形頭像),用戶(hù)沒(méi)有頭像時(shí)該項(xiàng)為空。若用戶(hù)更換頭像,原有頭像URL將失效。 |
| privilege | 用戶(hù)特權(quán)信息,json 數(shù)組,如微信沃卡用戶(hù)為(chinaunicom) |
| unionid | 只有在用戶(hù)將公眾號(hào)綁定到微信開(kāi)放平臺(tái)帳號(hào)后,才會(huì)出現(xiàn)該字段。 |
錯(cuò)誤時(shí)微信會(huì)返回JSON數(shù)據(jù)包如下(示例為openid無(wú)效):
{"errcode":40003,"errmsg":" invalid openid "}