微信開放平臺開發(3) 移動應用微信登入
在這篇微信公眾平臺開發教程中,我們將介紹如何使用微信開放平臺介面實現移動應用微信登入的功能。
移動應用微信登入是基於OAuth2.0協議標準構建的微信OAuth2.0授權登入系統。
在進行微信OAuth2.0授權登入接入之前,在微信開放平臺註冊開發者帳號,並擁有一個已稽核通過的移動應用,並獲得相應的AppID和AppSecret,申請微信登入且通過稽核後,可開始接入流程。
1、目前移動應用上微信登入只提供原生的登入方式,需要使用者安裝微信客戶端才能配合使用。
2、對於Android應用,建議總是顯示微信登入按鈕,當用戶手機沒有安裝微信客戶端時,請引導使用者下載安裝微信客戶端。
3、對於iOS應用,考慮到iOS應用商店稽核指南中的相關規定,建議開發者接入微信登入時,先檢測使用者手機是否已安裝微信客戶端(使用sdk中isWXAppInstalled函式 ),對未安裝的使用者隱藏微信登入按鈕,只提供其他登入方式(比如手機號註冊登入、遊客登入等)。
授權流程說明
微信OAuth2.0授權登入讓微信使用者使用微信身份安全登入第三方應用或網站,在微信使用者授權登入已接入微信OAuth2.0的第三方應用後,第三方可以獲取到使用者的介面呼叫憑證(access_token),通過access_token可以進行微信開放平臺授權關係介面呼叫,從而可實現獲取微信使用者基本開放資訊和幫助使用者實現基礎開放功能等。
微信OAuth2.0授權登入目前支援authorization_code模式,適用於擁有server端的應用授權。該模式整體流程為:
1. 第三方發起微信授權登入請求,微信使用者允許授權第三方應用後,微信會拉起應用或重定向到第三方網站,並且帶上授權臨時票據code引數;
2. 通過code引數加上AppID和AppSecret等,通過API換取access_token;
3. 通過access_token進行介面呼叫,獲取使用者基本資料資源或幫助使用者實現基本操作。
獲取access_token時序圖:
第一步:請求CODE
移動應用微信授權登入
開發者需要配合使用微信開放平臺提供的SDK進行授權登入請求接入。正確接入SDK後並擁有相關授權域(scope,什麼是授權域?)許可權後,開發者移動應用會在終端本地拉起微信應用進行授權登入,微信使用者確認後微信將拉起開發者移動應用,並帶上授權臨時票據(code)。
iOS平臺應用授權登入接入程式碼示例(請參考iOS接入指南):
-(void)sendAuthRequest { //構造SendAuthReq結構體 SendAuthReq* req =[[[SendAuthReq alloc ] init ] autorelease ]; req.scope = @"snsapi_userinfo" ; req.state = @"123" ; //第三方向微信終端傳送一個SendAuthReq訊息結構 [WXApi sendReq:req]; }
Android平臺應用授權登入接入程式碼示例(請參考Android接入指南):
{ // send oauth request Final SendAuth.Req req = new SendAuth.Req(); req.scope = "snsapi_userinfo"; req.state = "wechat_sdk_demo_test"; api.sendReq(req); }
引數說明
引數 | 是否必須 | 說明 |
---|---|---|
appid | 是 | 應用唯一標識,在微信開放平臺提交應用稽核通過後獲得 |
scope | 是 | 應用授權作用域,如獲取使用者個人資訊則填寫snsapi_userinfo(什麼是授權域?) |
state | 否 | 用於保持請求和回撥的狀態,授權請求後原樣帶回給第三方。該引數可用於防止csrf攻擊(跨站請求偽造攻擊),建議第三方帶上該引數,可設定為簡單的隨機數加session進行校驗 |
返回示例:
appid: wxd477edab60670232
scope: snsapi_userinfo
state: wechat_sdk_demo
可拉起微信開啟授權登入頁:
返回說明
使用者點選授權後,微信客戶端會被拉起,跳轉至授權介面,使用者在該介面點選允許或取消,SDK通過SendAuth的Resp返回資料給呼叫方。
返回值 | 說明 |
---|---|
ErrCode | ERR_OK = 0(使用者同意) ERR_AUTH_DENIED = -4(使用者拒絕授權) ERR_USER_CANCEL = -2(使用者取消) |
code | 使用者換取access_token的code,僅在ErrCode為0時有效 |
state | 第三方程式傳送時用來標識其請求的唯一性的標誌,由第三方程式呼叫sendReq時傳入,由微信終端回傳,state字串長度不能超過1K |
lang | 微信客戶端當前語言 |
country | 微信使用者當前國家資訊 |
第二步:通過code獲取access_token
獲取第一步的code後,請求以下連結獲取access_token:
https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
引數說明
引數 | 是否必須 | 說明 |
---|---|---|
appid | 是 | 應用唯一標識,在微信開放平臺提交應用稽核通過後獲得 |
secret | 是 | 應用金鑰AppSecret,在微信開放平臺提交應用稽核通過後獲得 |
code | 是 | 填寫第一步獲取的code引數 |
grant_type | 是 | 填authorization_code |
返回如下
{ "access_token": "OezXcEiiBSKSxW0eoylIeOZ0dfxvb93UyrFdwznvwUv3JkVNVV1yFvQQa3IfuyMi4iZGDsAfe81sCaUXxyKrI-5XgCvhAS02eAC4MF2fJFl80Y9s-0h1EsuBmIVKgu0GnKhxCQ0M8G-gkQAJpzLzmQ", "expires_in": 7200, "refresh_token": "OezXcEiiBSKSxW0eoylIeOZ0dfxvb93UyrFdwznvwUv3JkVNVV1yFvQQa3IfuyMiH7dCabGFyMRtZHnHPHuEK78cf1eISYJ4y453T8pDa2tFAIJu8bFeLMBpeFSv9dgnGrK-ZfRxHzhq7IW4qevEMQ", "openid": "oH9d2v7NmDhsFzICG63UPSIOgUcY", "scope": "snsapi_userinfo", "unionid": "o4wcnwx0BVC4F_hSl5qCd5rC4Jps" }
引數說明
引數 | 說明 |
---|---|
access_token | 介面呼叫憑證 |
expires_in | access_token介面呼叫憑證超時時間,單位(秒) |
refresh_token | 使用者重新整理access_token |
openid | 授權使用者唯一標識 |
scope | 使用者授權的作用域,使用逗號(,)分隔 |
unionid | 當且僅當該移動應用已獲得該使用者的userinfo授權時,才會出現該欄位 |
獲取使用者個人資訊(UnionID機制)
介面說明
此介面用於獲取使用者個人資訊。開發者可通過OpenID來獲取使用者基本資訊。特別需要注意的是,如果開發者擁有多個移動應用、網站應用和公眾帳號,可通過獲取使用者基本資訊中的unionid來區分使用者的唯一性,因為只要是同一個微信開放平臺帳號下的移動應用、網站應用和公眾帳號,使用者的unionid是唯一的。換句話說,同一使用者,對同一個微信開放平臺下的不同應用,unionid是相同的。請注意,在使用者修改微信頭像後,舊的微信頭像URL將會失效,因此開發者應該自己在獲取使用者資訊後,將頭像圖片儲存下來,避免微信頭像URL失效後的異常情況。
請求說明
http請求方式: GET
https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID
引數說明
引數 | 是否必須 | 說明 |
---|---|---|
access_token | 是 | 呼叫憑證 |
openid | 是 | 普通使用者的標識,對當前開發者帳號唯一 |
lang | 否 | 國家地區語言版本,zh_CN 簡體,zh_TW 繁體,en 英語,預設為zh-CN |
{ "openid": "oH9d2v7NmDhsFzICG63UPSIOgUcY", "nickname": "方倍", "sex": 0, "language": "zh_CN", "city": "", "province": "", "country": "CN", "headimgurl": "http://wx.qlogo.cn/mmopen/pburdzLK7PUTcFw3ozK52Gravkznno51DSjnqnzsG6WzJLUOtadGBYYSVqh5YDicdawxrD6hHoR96OcyyDWAEgA/0", "privilege": [], "unionid": "o4wcnwx0BVC4F_hSl5qCd5rC4Jps" }
引數說明
引數 | 說明 |
---|---|
openid | 普通使用者的標識,對當前開發者帳號唯一 |
nickname | 普通使用者暱稱 |
sex | 普通使用者性別,1為男性,2為女性 |
province | 普通使用者個人資料填寫的省份 |
city | 普通使用者個人資料填寫的城市 |
country | 國家,如中國為CN |
headimgurl | 使用者頭像,最後一個數值代表正方形頭像大小(有0、46、64、96、132數值可選,0代表640*640正方形頭像),使用者沒有頭像時該項為空 |
privilege | 使用者特權資訊,json陣列,如微信沃卡使用者為(chinaunicom) |
unionid | 使用者統一標識。針對一個微信開放平臺帳號下的應用,同一使用者的unionid是唯一的。 |
完整PHP SDK
class class_app { var $appid = APPID; var $appsecret = APPSECRET; //建構函式 public function __construct($appid = NULL, $appsecret = NULL) { if($appid && $appsecret){ $this->appid = $appid; $this->appsecret = $appsecret; } } //通過code獲取access_token public function oauth2_access_token($code) { $url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=".$this->appid."&secret=".$this->appsecret."&code=".$code."&grant_type=authorization_code"; $res = $this->http_request($url); return json_decode($res, true); } //獲取使用者個人資訊(UnionID機制) public function oauth2_get_user_info($access_token, $openid) { $url = "https://api.weixin.qq.com/sns/userinfo?access_token=".$access_token."&openid=".$openid."&lang=zh_CN"; $res = $this->http_request($url); return json_decode($res, true); } //HTTP請求(支援HTTP/HTTPS,支援GET/POST) protected function http_request($url, $data = null) { $curl = curl_init(); curl_setopt($curl, CURLOPT_URL, $url); curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE); curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE); if (!empty($data)){ curl_setopt($curl, CURLOPT_POST, 1); curl_setopt($curl, CURLOPT_POSTFIELDS, $data); } curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE); $output = curl_exec($curl); curl_close($curl); return $output; } //日誌記錄 private function logger($log_content) { if(isset($_SERVER['HTTP_APPNAME'])){ //SAE sae_set_display_errors(false); sae_debug($log_content); sae_set_display_errors(true); }else if($_SERVER['REMOTE_ADDR'] != "127.0.0.1"){ //LOCAL $max_size = 500000; $log_filename = "log.xml"; if(file_exists($log_filename) and (abs(filesize($log_filename)) > $max_size)){unlink($log_filename);} file_put_contents($log_filename, date('Y-m-d H:i:s').$log_content."\r\n", FILE_APPEND); } } }
呼叫方法
/* 方倍工作室 http://www.fangbei.org/ CopyRight 2014 All Rights Reserved 微信開放平臺 移動應用 (微信登入) */ header("Content-type: text/html; charset=utf-8"); define('APPID', "wx3f05f4b79761d123"); define('APPSECRET', "9acc222b92afb29cff90b9bcfc7d6080"); $code = "041359a1b393c92a5a509ce24e2ef50f"; $weixin = new class_app(); var_dump($weixin); //傳入授權臨時票據(code) $oauth2_info = $weixin->oauth2_access_token($code); var_dump($oauth2_info); $result = $weixin->oauth2_get_user_info($oauth2_info['access_token'], $oauth2_info['openid']); var_dump($result);