公眾號授權給第三方平台的技術實現流程比較複雜。具體步驟講解如下。
步驟1:微信服務器向第三方平台消息接收地址推送component_verify_ticket。
出於安全考慮,在第三方平台創建審核通過後,微信服務器每隔10分鐘會向第三方的消息接收地址推送一次component_verify_ticket,用於獲取第三方平台接口調用憑據。
微信服務器發送給服務自身的事件推送(如取消授權通知、Ticket推送等)中,XML消息體中沒有ToUserName字段,而是AppID字段,即公眾號服務的AppID。這種系統事件推送通知(現在包括推送component_verify_ticket協議和推送取消授權通知),服務開發者收到後也需進行解密,接收到後只需直接返回字符串「success」。
1 require_once('config.php'); 2 require_once('crypt/wxBizMsgCrypt.php'); 3 4 $signature = $_GET['signature']; 5 $timestamp = $_GET['timestamp']; 6 $nonce = $_GET['nonce']; 7 $encrypt_type = $_GET['encrypt_type']; 8 $msg_signature = $_GET['msg_signature']; 9 $postStr = $GLOBALS["HTTP_RAW_POST_DATA"]; 10 11 // 解密 12 $pc = new WXBizMsgCrypt(Token, EncodingAESKey, AppID); 13 $decryptMsg = ""; // 解密後的明文 14 $errCode = $pc->DecryptMsg($msg_signature, $timestamp, $nonce, $postStr, $decryptMsg); 15 $postStr = $decryptMsg; 16 17 $postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA); 18 $INFO_TYPE = trim($postObj->InfoType); 19 20 // 消息類型分離 21 switch ($INFO_TYPE) 22 { 23 case "component_verify_ticket": 24 $component_verify_ticket = $postObj->ComponentVerifyTicket; 25 // 更新component_verify_ticket到系統中 26 file_put_contents('component_verify_ticket.json', '{"component_verify_ticket": "'.$postObj->ComponentVerifyTicket.'", "component_expires_time": '.time.'}'); 27 $result = "success"; 28 break; 29 default: 30 $result = "unknown msg type: ".$INFO_TYPE; 31 break; 32 } 33 echo $result;
上述代碼解讀如下。
第4~9行:接收URL中GET參數的值,以及POST傳過來的數據。
第11~15行:將發送過來的加密消息進行解密。
第17~18行:將解密後的XML字符串轉換成對象。
第21~32行:檢查消息類型,如果類型是component_verify_ticket,則獲取對像中的ComponentVerifyTicket值,並存入本地文件中,同時設置返回內容為「success」。
第33行:回顯返回內容給服務器。
在微信開放平台後台中,授權事件接收地址接收到的鏈接如下。
http:// open.fangbei.org/wxopen/auth.php?signature=745e6b4b2fee9e59810e120888d22e927965e1fd×tamp=1465800084&nonce=469026211&encrypt_type=aes&msg_signature=b722cd5cab3110f4c78d3e49973fba0f402f986e
POST傳過來的數據如下。
<xml> <AppId><![CDATA[wx2ae3853dda623211]]></AppId> <Encrypt><![CDATA[JUdOMf32n9KarWBx6o4bTHmY5lzuksWJfvomNVKKeyDxWM/1Nz0jysradXmD/ FReeylakkLivi// gsk0YOTY7smreY+sdmNsLDF3TIezdwqh3a2M8Qk3jcxAbWogBpp4b7apbVoiEa HSnpuFSVL84KabVqoS+Y33Z3sD8YYHDWlx1Edr/D3VWzocbmcUuDvoDcDJbVf6NN8ENPO4vRqaIj KWli0JyJYQGHU5y9YfjOr72nTYk5p7/NvXCHVxr6mfBQ0z/eytz1RxUT9rHh9QwfbthzWccmUbyk y2ILm1cSQJsH3l19nzViUZIVF5I53da/qXXK9q4YbvtIuFEMBPB5VjgRRqW4kudT2UNuy8qwnL9n IW1cE+eOoh4AUYpyuMelrNMaTAhRLDicsfphOoENiigVGoeChlm0kgzE6NMWyGIS1XQ1rjElbJ1h xuM8d4qlHL6EA6ppPPJreysPLP9Q==]]></Encrypt> </xml>
解密後的內容如下。
<xml> <AppId><![CDATA[wx2ae3853dda623211]]></AppId> <CreateTime>1465800084</CreateTime> <InfoType><![CDATA[component_verify_ticket]]></InfoType> <ComponentVerifyTicket><![CDATA[ticket@@@rPTvFYrZWLRgV-3iKj5VNBSWadDJGJh0YhzJ- oteCpLz0lX83e9npHXFy3WsM31H-UyzYhdUMcW20QyNyuyYmQ]]></ComponentVerifyTicket> </xml>
上述數據的參數說明如表22-18所示。
表22-18 ComponentVerifyTicket協議參數說明
可以看到,這次接收到的component_verify_ticket的值為「ticket@@@rPTvFYrZWLRgV-3iKj5VNBSWadDJGJh0YhzJ-oteCpLz0lX83e9npHXFy3WsM31H-UyzYhdUMcW20QyNyuyYmQ」。
步驟2:第三方平台獲取component_access_token。
compoment_access_token是第三方平台的接口調用憑據,也稱為令牌。每個令牌是存在有效期(2小時)的,且令牌的調用不是無限制的。開發人員需要對第三方平台做好令牌管理,在令牌快過期時(如1小時50分)進行刷新。
compoment_access_token需要通過component_appid和component_appsecret(即微信開放平台管理中心的第三方平台詳情頁中的AppID和AppSecret),以及component_verify_ticket(每10分鐘推送一次的安全ticket)來獲取自己的接口調用憑據(component_access_token)。
獲取第三方平台component_access_token的接口如下。
https:// api.weixin.qq.com/cgi-bin/component/api_component_token
獲取第三方平台component_access_token時,POST數據示例如下。
{ "component_appid":"appid_value", "component_appsecret":"appsecret_value", "component_verify_ticket":"ticket_value" }
上述數據的參數說明如表22-19所示。
表22-19 獲取第三方平台component_access_token接口的參數說明
正確創建時,返回的數據示例如下。
{ "component_access_token":"61W3mEpU66027wgNZ_MhGHNQDHnFATkDa9-2llqrMBjUwxRSNPbVsMmyD- yq8wZETSoE5NQgecigDrSHkPtIYA", "expires_in":7200 }
上述數據的參數說明如表22-20所示。
表22-20 獲取第三方平台component_access_token接口返回參數說明
獲取第三方平台component_access_token的代碼如下。
1 class class_wxthird 2 { 3 // 構造函數 2、獲取第三方平台component_access_token 4 public function __construct 5 { 6 $this->component_appid = AppID; 7 $this->component_appsecret = AppSecret; 8 9 // 文件緩存 component_verify_ticket 10 $res = file_get_contents('component_verify_ticket.json'); 11 $result = json_decode($res, true); 12 $this->component_verify_ticket = $result["component_verify_ticket"]; 13 14 // 文件緩存 component_access_token 15 $res = file_get_contents('component_access_token.json'); 16 $result = json_decode($res, true); 17 $this->component_access_token = $result["component_access_token"]; 18 $this->component_expires_time = $result["component_expires_time"]; 19 if ((time > ($this->component_expires_time + 3600)) || (empty($this- >component_access_token))){ 20 $component = array('component_appid' => $this->component_appid,'component_ appsecret' => $this->component_appsecret,'component_verify_ticket' => $this->component_verify_ticket); 21 $data = urldecode(json_encode($component)); 22 $url = "https:// api.weixin.qq.com/cgi-bin/component/api_component_token"; 23 $res = $this->http_request($url, $data); 24 $result = json_decode($res, true); 25 $this->component_access_token = $result["component_access_token"]; 26 $this->component_expires_time = time; 27 file_put_contents('component_access_token.json', '{"component_access_token": "'.$this->component_access_token.'", "component_expires_time": '. $this->component_expires_time.'}'); 28 } 29 } 30 }
步驟3:獲取預授權碼pre_auth_code和授權碼auth_code。
預授權碼用於公眾號授權時的第三方平台安全驗證。
獲取預授權碼pre_auth_code的接口如下。
https:// api.weixin.qq.com/cgi-bin/component/api_create_preauthcode?component_access_token=xxx
獲取預授權碼pre_auth_code時,POST數據示例如下。
{ "component_appid":"appid_value" }
上述數據的參數說明如表22-21所示。
表22-21 獲取預授權碼pre_auth_code接口的參數說明
正確創建時,返回的數據示例如下。
{ "pre_auth_code":"Cx_Dk6qiBE0Dmx4EmlT3oRfArPvwSQ-oa3NL_fwHM7VI08r52wazoZX2Rhpz1dEw", "expires_in":600 }
上述數據的參數說明如表22-22所示。
表22-22 獲取預授權碼pre_auth_code接口返回參數說明
上述接口已獲得預授權碼,接下來通過預授權碼獲得授權碼。
第三方平台可以在自己的網站中放置「微信公眾號授權」的入口,引導公眾號運營者進入授權頁。授權頁網址如下。
https:// mp.weixin.qq.com/cgi-bin/componentloginpage?component_appid=xxxx&pre_auth_code=xxxxx&redirect_uri=xxxx
該網址中第三方平台需要提供第三方平台AppID、預授權碼和回調URI。
用戶進入第三方平台授權頁後,需要確認並同意將自己的公眾號登錄授權給第三方平台,完成授權流程。公眾號授權頁面如圖22-9所示。
圖22-9 公眾號授權
授權流程完成後,授權頁會自動跳轉進入回調URI,並在URL參數中返回授權碼(authorization_code)和過期時間。其鏈接如下。
http:// open.fangbei.org/wxopen/login.php?auth_code=queryauthcode@@@781GTHj_A0GOQ2v7vidjMLhGlKNEhFlJHt9G6cqYxIXGS0ECe433gLGGusd-Q5OURs9Mgg7ukaWbY59htR-shw&expires_in=3600
URL中的auth_code即為授權碼參數。
步驟4:獲取接口調用憑據和授權信息。
開發者需要使用授權碼換取授權公眾號的授權信息,並換取authorizer_access_token和authorizer_refresh_token授權碼的獲取,需要用戶在第三方平台授權頁中完成授權流程後,在回調URI中通過URL參數提供給第三方平台。
調用憑據和授權信息的接口如下。
https:// api.weixin.qq.com/cgi-bin/component/api_query_auth?component_access_token=xxxx
調用憑據和授權信息時,POST數據示例如下。
{ "component_appid":"appid_value", "authorization_code":"auth_code_value" }
上述數據的參數說明如表22-23所示。
表22-23 調用憑據和授權信息接口的參數說明
正確創建時,返回的數據示例如下。
{ "authorization_info": { "authorizer_appid": "wx1b7559b818e3c23e", "authorizer_access_token": "W8dOXLQikO51MtMGIeMchqCnAMhS_ZyZpnIK_3YtReGJm37EF6 rjNKRD3GoRpMcT3KcVBtE68xTxGb7z3b8ba4i7zNkhfEQL9hCJD6pdQIJhcv6j8cFlHZnvQWrvA34 hUKMcAMDYOQ", "expires_in": 7200, "authorizer_refresh_token": "refreshtoken@@@kIi8GNH-Pjrha0bdgGBSYvcwedz0e6xhO 157YkXKrk8", "func_info": [ {"funcscope_category": {"id": 1 }}, {"funcscope_category": {"id": 15 }}, {"funcscope_category": {"id": 7 }}, {"funcscope_category": {"id": 2 }}, {"funcscope_category": {"id": 3 }}, {"funcscope_category": {"id": 6 }}, {"funcscope_category": {"id": 8 }}, {"funcscope_category": {"id": 13 }}, {"funcscope_category": {"id": 9 }}, {"funcscope_category": {"id": 12 }} ] } }
上述數據的參數說明如表22-24所示。
表22-24 調用憑據和授權信息接口返回參數說明
步驟5:獲取授權方公眾號的基本信息。
授權方公眾號的基本信息包括頭像、暱稱、賬號類型、認證類型、微信號、原始ID和二維碼圖片的URL。
獲取授權公眾號基本信息的接口如下。
https:// api.weixin.qq.com/cgi-bin/component/api_get_authorizer_info?component_access_token=xxxx
獲取授權公眾號的基本信息時,POST數據示例如下。
{ "component_appid":"appid_value", "authorizer_appid":"auth_appid_value" }
上述數據的參數說明如表22-25所示。
表22-25 獲取授權公眾號基本信息接口的參數說明
正確創建時,返回的數據示例如下。
{ "authorizer_info":{ "nick_name":"方倍工作室", "head_img":"http:// wx.qlogo.cn/mmopen/JThERPIYjcWWaHpwW7YQlkZfl1UL9dIu0to4kFY 2V3Inyzc4cQRa87b0xJWUg5axn30r1kNlu4ueK5Bf8tapT3vVfNjvFcoib/0", "service_type_info":{"id":2}, "verify_type_info":{"id":0}, "user_name":"gh_fcc4da210ff0", "alias":"fbxxjs", "qrcode_url":"http:// mmbiz.qpic.cn/mmbiz/BIvw3ibibwAYMdZIyVZHeia0mt12LT5x nXUdhvP9AeA2uQAlka5Y2ibbBFPwicSib2TxQTSd2NjVtANkBTTp2sGibTOcw/0", "business_info":{ "open_pay":1, "open_shake":1, "open_scan":0, "open_card":1, "open_store":1 }, "idc":1 }, "authorization_info":{ "authorizer_appid":"wx1b7559b818e3c23e", "func_info":[ {"funcscope_category":{"id":1 }}, {"funcscope_category":{"id":15}}, {"funcscope_category":{"id":7 }}, {"funcscope_category":{"id":2 }}, {"funcscope_category":{"id":3 }}, {"funcscope_category":{"id":6 }}, {"funcscope_category":{"id":8 }}, {"funcscope_category":{"id":13}}, {"funcscope_category":{"id":9 }}, {"funcscope_category":{"id":12}} ] } }
上述數據的參數說明如表22-26所示。
表22-26 獲取授權公眾號基本信息接口返回參數說明
公眾號授權第三方平台的代碼如下。
$weixin = new class_wxthird; if (!isset($_GET["auth_code"])){ $result = $weixin->get_pre_auth_code; $pre_auth_code = $result["pre_auth_code"]; $redirect_uri = 'http:// '.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']; $jumpurl = $weixin->component_login_page($pre_auth_code, $redirect_uri); Header("Location: $jumpurl"); }else{ $authorization = $weixin->query_authorization($_GET["auth_code"]); $authorizer_appid = $authorization["authorization_info"]["authorizer_appid"]; $authorizer_info = $weixin->get_authorizer_info($authorizer_appid); var_dump($authorizer_info); }
步驟6:代公眾號發起業務。
得到接口調用憑據後,第三方平台可以按照公眾號開發者文檔(mp.weixin.qq.com/wiki)的說明,調用公眾號相關API(能調用哪些API,取決於用戶將哪些權限集授權給了第三方平台,也取決於公眾號自身擁有哪些接口權限),使用JS SDK等能力。
下面是代公眾號調用客服接口的SDK函數的代碼。
1 // 代發客服接口消息 2 public function send_custom_message($openid, $type, $data, $authorizer_access_token) 3 { 4 $msg = array('touser' =>$openid); 5 $msg['msgtype'] = $type; 6 switch($type) 7 { 8 case 'text': 9 $msg[$type] = array('content'=>urlencode($data)); 10 break; 11 case 'news': 12 $data2 = array; 13 foreach ($data as &$item) { 14 $item2 = array; 15 foreach ($item as $k => $v) { 16 $item2[strtolower($k)] = urlencode($v); 17 } 18 $data2 = $item2; 19 } 20 $msg[$type] = array('articles'=>$data2); 21 break; 22 case 'music': 23 case 'image': 24 case 'voice': 25 case 'video': 26 $msg[$type] = $data; 27 break; 28 default: 29 $msg['text'] = array('content'=>urlencode("不支持的消息類型 ".$type)); 30 break; 31 } 32 $url = "https:// api.weixin.qq.com/cgi-bin/message/custom/send?access_token=". $authorizer_access_token; 33 return $this->http_request($url, urldecode(json_encode($msg))); 34 }
可以看到,其接口及參數定義和公眾號本身的發送客服消息接口是一致的,唯一不同的是把公眾號的access_token換成了第三方平台的authorizer_access_token。
該接口的調用示例代碼如下。
1 require_once('wxthird.class.php'); 2 $weixin = new class_wxthird; 3 $openid = "ozy4qt1eDxSxzCr0aNT0mXCWfrDE"; 4 $authorizer_access_token = "W8dOXLQikO51MtMGIeMchqCnAMhS_ZyZpnIK_3YtReGJm37EF6 rjNKRD3GoRpMcT3KcVBtE68xTxGb7z3b8ba4i7zNkhfEQL9hCJD6pdQIJhcv6j8cFlHZnvQWrvA 34hUKMcAMDYOQ"; 5 $result = $weixin->send_custom_message($openid, "text", "這是第三方平台通過客服接口 發送的文本消息", $authorizer_access_token);