官方網站:http://oauth.net/ http://oauth.net/2/php
權威定義:OAuth is An open protocol to allow secure authorization in a simple and standard method from web, mobile and desktop applications. web
OAuth是一個開放協議,容許用戶讓第三方應用以安全且標準的方式獲取該用戶在某一網站、移動或桌面應用上存儲的私密的資源(如用戶我的信息、照片、視頻、聯繫人列表),而無需將用戶名和密碼提供給第三方應用。json
OAuth 2.0是OAuth協議的下一版本,但不向後兼容OAuth 1.0。 OAuth 2.0關注客戶端開發者的簡易性,同時爲Web應用,桌面應用和手機,和起居室設備提供專門的認證流程。api
OAuth容許用戶提供一個令牌,而不是用戶名和密碼來訪問他們存放在特定服務提供者的數據。每個令牌受權一個特定的網站(例如,視頻編輯網站)在特定的時段(例如,接下來的2小時內)內訪問特定的資源(例如僅僅是某一相冊中的視頻)。這樣,OAuth容許用戶受權第三方網站訪問他們存儲在另外的服務提供者上的信息,而不須要分享他們的訪問許可或他們數據的全部內容。數組
新浪微博API目前也使用OAuth 2.0。安全
大致流程以下圖:服務器
用戶首先請求第三方網頁微信
第三方服務器獲取用戶請求後會進行判斷,是否須要獲取code(正常請求確定是須要code的,這裏咱們能夠參考一下官方JsApiPay的mode,來看獲取openid的大致流程)app
1 <?php 2 require_once "../lib/WxPay.Api.php"; 3 /** 4 * 5 * JSAPI支付實現類 6 * 該類實現了從微信公衆平臺獲取code、經過code獲取openid和access_token、 7 * 生成jsapi支付js接口所需的參數、生成獲取共享收貨地址所需的參數 8 * 9 * 該類是微信支付提供的樣例程序,商戶可根據本身的需求修改,或者使用lib中的api自行開發 10 * 11 * @author widy 12 * 13 */ 14 class JsApiPay 15 { 16 /** 17 * 18 * 網頁受權接口微信服務器返回的數據,返回樣例以下 19 * { 20 * "access_token":"ACCESS_TOKEN", 21 * "expires_in":7200, 22 * "refresh_token":"REFRESH_TOKEN", 23 * "openid":"OPENID", 24 * "scope":"SCOPE", 25 * "unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL" 26 * } 27 * 其中access_token可用於獲取共享收貨地址 28 * openid是微信支付jsapi支付接口必須的參數 29 * @var array 30 */ 31 public $data = null; 32 33 /** 34 * 35 * 經過跳轉獲取用戶的openid,跳轉流程以下: 36 * 一、設置本身須要調回的url及其其餘參數,跳轉到微信服務器https://open.weixin.qq.com/connect/oauth2/authorize 37 * 二、微信服務處理完成以後會跳轉回用戶redirect_uri地址,此時會帶上一些參數,如:code 38 * 39 * @return 用戶的openid 40 */ 41 public function GetOpenid() 42 { 43 //經過code得到openid 44 if (!isset($_GET['code'])){ 45 //觸發微信返回code碼 46 $baseUrl = urlencode('http://'.$_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF'].$_SERVER['QUERY_STRING']); 47 $url = $this->__CreateOauthUrlForCode($baseUrl); 48 Header("Location: $url"); 49 exit(); 50 } else { 51 //獲取code碼,以獲取openid 52 $code = $_GET['code']; 53 $openid = $this->getOpenidFromMp($code); 54 return $openid; 55 } 56 } 57 58 /** 59 * 60 * 獲取jsapi支付的參數 61 * @param array $UnifiedOrderResult 統一支付接口返回的數據 62 * @throws WxPayException 63 * 64 * @return json數據,可直接填入js函數做爲參數 65 */ 66 public function GetJsApiParameters($UnifiedOrderResult) 67 { 68 if(!array_key_exists("appid", $UnifiedOrderResult) 69 || !array_key_exists("prepay_id", $UnifiedOrderResult) 70 || $UnifiedOrderResult['prepay_id'] == "") 71 { 72 throw new WxPayException("參數錯誤"); 73 } 74 $jsapi = new WxPayJsApiPay(); 75 $jsapi->SetAppid($UnifiedOrderResult["appid"]); 76 $timeStamp = time(); 77 $jsapi->SetTimeStamp("$timeStamp"); 78 $jsapi->SetNonceStr(WxPayApi::getNonceStr()); 79 $jsapi->SetPackage("prepay_id=" . $UnifiedOrderResult['prepay_id']); 80 $jsapi->SetSignType("MD5"); 81 $jsapi->SetPaySign($jsapi->MakeSign()); 82 $parameters = json_encode($jsapi->GetValues()); 83 return $parameters; 84 } 85 86 /** 87 * 88 * 經過code從工做平臺獲取openid機器access_token 89 * @param string $code 微信跳轉回來帶上的code 90 * 91 * @return openid 92 */ 93 public function GetOpenidFromMp($code) 94 { 95 $url = $this->__CreateOauthUrlForOpenid($code); 96 //初始化curl 97 $ch = curl_init(); 98 //設置超時 99 curl_setopt($ch, CURLOPT_TIMEOUT, $this->curl_timeout); 100 curl_setopt($ch, CURLOPT_URL, $url); 101 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER,FALSE); 102 curl_setopt($ch, CURLOPT_SSL_VERIFYHOST,FALSE); 103 curl_setopt($ch, CURLOPT_HEADER, FALSE); 104 curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); 105 if(WxPayConfig::CURL_PROXY_HOST != "0.0.0.0" 106 && WxPayConfig::CURL_PROXY_PORT != 0){ 107 curl_setopt($ch,CURLOPT_PROXY, WxPayConfig::CURL_PROXY_HOST); 108 curl_setopt($ch,CURLOPT_PROXYPORT, WxPayConfig::CURL_PROXY_PORT); 109 } 110 //運行curl,結果以jason形式返回 111 $res = curl_exec($ch); 112 curl_close($ch); 113 //取出openid 114 $data = json_decode($res,true); 115 $this->data = $data; 116 $openid = $data['openid']; 117 return $openid; 118 } 119 120 /** 121 * 122 * 拼接簽名字符串 123 * @param array $urlObj 124 * 125 * @return 返回已經拼接好的字符串 126 */ 127 private function ToUrlParams($urlObj) 128 { 129 $buff = ""; 130 foreach ($urlObj as $k => $v) 131 { 132 if($k != "sign"){ 133 $buff .= $k . "=" . $v . "&"; 134 } 135 } 136 137 $buff = trim($buff, "&"); 138 return $buff; 139 } 140 141 /** 142 * 143 * 獲取地址js參數 144 * 145 * @return 獲取共享收貨地址js函數須要的參數,json格式能夠直接作參數使用 146 */ 147 public function GetEditAddressParameters() 148 { 149 $getData = $this->data; 150 $data = array(); 151 $data["appid"] = WxPayConfig::APPID; 152 $data["url"] = "http://".$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']; 153 $time = time(); 154 $data["timestamp"] = "$time"; 155 $data["noncestr"] = "1234568"; 156 $data["accesstoken"] = $getData["access_token"]; 157 ksort($data); 158 $params = $this->ToUrlParams($data); 159 $addrSign = sha1($params); 160 161 $afterData = array( 162 "addrSign" => $addrSign, 163 "signType" => "sha1", 164 "scope" => "jsapi_address", 165 "appId" => WxPayConfig::APPID, 166 "timeStamp" => $data["timestamp"], 167 "nonceStr" => $data["noncestr"] 168 ); 169 $parameters = json_encode($afterData); 170 return $parameters; 171 } 172 173 /** 174 * 175 * 構造獲取code的url鏈接 176 * @param string $redirectUrl 微信服務器回跳的url,須要url編碼 177 * 178 * @return 返回構造好的url 179 */ 180 private function __CreateOauthUrlForCode($redirectUrl) 181 { 182 $urlObj["appid"] = WxPayConfig::APPID; 183 $urlObj["redirect_uri"] = "$redirectUrl"; 184 $urlObj["response_type"] = "code"; 185 $urlObj["scope"] = "snsapi_base"; 186 $urlObj["state"] = "STATE"."#wechat_redirect"; 187 $bizString = $this->ToUrlParams($urlObj); 188 return "https://open.weixin.qq.com/connect/oauth2/authorize?".$bizString; 189 } 190 191 /** 192 * 193 * 構造獲取open和access_toke的url地址 194 * @param string $code,微信跳轉帶回的code 195 * 196 * @return 請求的url 197 */ 198 private function __CreateOauthUrlForOpenid($code) 199 { 200 $urlObj["appid"] = WxPayConfig::APPID; 201 $urlObj["secret"] = WxPayConfig::APPSECRET; 202 $urlObj["code"] = $code; 203 $urlObj["grant_type"] = "authorization_code"; 204 $bizString = $this->ToUrlParams($urlObj); 205 return "https://api.weixin.qq.com/sns/oauth2/access_token?".$bizString; 206 } 207 }
若是須要獲取code,第三方服務器會跳轉到受權頁面微信公衆平臺
在確保微信公衆帳號擁有受權做用域(scope參數)的權限的前提下(服務號得到高級接口後,默認擁有scope參數中的snsapi_base和snsapi_userinfo),引導關注者打開以下頁面
請求方法以下:
https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect 若提示「該連接沒法訪問」,請檢查參數是否填寫錯誤,是否擁有scope參數對應的受權做用域權限。
參數說明:
參數 | 必須 | 說明 |
---|---|---|
appid | 是 | 公衆號的惟一標識 |
redirect_uri | 是 | 受權後重定向的回調連接地址 |
response_type | 是 | 返回類型,請填寫code |
scope | 是 | 應用受權做用域,snsapi_base (不彈出受權頁面,直接跳轉,只能獲取用戶openid),snsapi_userinfo (彈出受權頁面,可經過openid拿到暱稱、性別、所在地。而且,即便在未關注的狀況下,只要用戶受權,也能獲取其信息) |
state | 否 | 重定向後會帶上state參數,開發者能夠填寫任意參數值 |
#wechat_redirect | 否 | 直接在微信打開連接,能夠不填此參數。作頁面302重定向時候,必須帶此參數 |
下圖爲scope等於snsapi_userinfo時的受權頁面:
用戶贊成受權將信息發送到微信公衆平臺,微信公衆平臺會內部進行受權驗證
用戶贊成受權,頁面將跳轉至 redirect_uri/?code=CODE&state=STATE。
code說明 : code做爲換取access_token的票據,每次用戶受權帶上的code將不同,code只能使用一次,5分鐘未被使用自動過時。
驗證經過返回給第三方服務器code
經過code換取網頁受權access_token
首先請注意,這裏經過code換取的是一個特殊的網頁受權access_token,與基礎支持中的access_token(該access_token用於調用其餘接口)不一樣。公衆號可經過下述接口來獲取網頁受權access_token。若是網頁受權的做用域爲snsapi_base,則本步驟中獲取到網頁受權access_token的同時,也獲取到了openid,snsapi_base式的網頁受權流程即到此爲止。
請求方法以下:
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 |
返回說明:
正確時返回的JSON數據包以下:
{ "access_token":"ACCESS_TOKEN", "expires_in":7200, "refresh_token":"REFRESH_TOKEN", "openid":"OPENID", "scope":"SCOPE" }
參數說明:
參數 | 描述 |
---|---|
access_token | 網頁受權接口調用憑證,注意:此access_token與基礎支持的access_token不一樣 |
expires_in | access_token接口調用憑證超時時間,單位(秒) |
refresh_token | 用戶刷新access_token |
openid | 用戶惟一標識,請注意,在未關注公衆號時,用戶訪問公衆號的網頁,也會產生一個用戶和公衆號惟一的OpenID |
scope | 用戶受權的做用域,使用逗號(,)分隔 |
錯誤時微信會返回JSON數據包以下(示例爲Code無效錯誤):
{"errcode":40029,"errmsg":"invalid code"}
若是access_token過時了須要從新刷取access_token(初次使用能夠先忽略)
請求方法以下:
https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=APPID&grant_type=refresh_token&refresh_token=REFRESH_TOKEN
參數說明:
參數 | 是否必須 | 說明 |
---|---|---|
appid | 是 | 公衆號的惟一標識 |
grant_type | 是 | 填寫爲refresh_token |
refresh_token | 是 | 填寫經過access_token獲取到的refresh_token參數 |
官方文檔有說明,須要scope爲snsapi_userinfo
請求方法以下:
http:GET(請使用https協議) https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN
參數說明:
參數 | 描述 |
---|---|
access_token | 網頁受權接口調用憑證,注意:此access_token與基礎支持的access_token不一樣 |
openid | 用戶的惟一標識 |
返回說明
正確時返回的JSON數據包以下:
{ "openid":" OPENID", " nickname": NICKNAME, "sex":"1", "province":"PROVINCE" "city":"CITY", "country":"COUNTRY", "headimgurl": "http://wx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ 4eMsv84eavHiaiceqxibJxCfHe/46", "privilege":[ "PRIVILEGE1" "PRIVILEGE2" ], "unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL" }
參數說明:
參數 | 描述 |
---|---|
openid | 用戶的惟一標識 |
nickname | 用戶暱稱 |
sex | 用戶的性別,值爲1時是男性,值爲2時是女性,值爲0時是未知 |
province | 用戶我的資料填寫的省份 |
city | 普通用戶我的資料填寫的城市 |
country | 國家,如中國爲CN |
headimgurl | 用戶頭像,最後一個數值表明正方形頭像大小(有0、4六、6四、9六、132數值可選,0表明640*640正方形頭像),用戶沒有頭像時該項爲空 |
privilege | 用戶特權信息,json 數組,如微信沃卡用戶爲(chinaunicom) |
錯誤時微信會返回JSON數據包以下(示例爲openid無效):
{"errcode":40003,"errmsg":" invalid openid "}
其餘一些細節性的問題請參考官方文檔:https://mp.weixin.qq.com/wiki