微信公眾平臺開發 OAuth2.0網頁授權認證
一、什麼是OAuth2.0
官方網站:http://oauth.net/ http://oauth.net/2/
權威定義:OAuth is An open protocol to allow secure authorization in a simple and standard method from web, mobile and desktop applications.
OAuth是一個開放協議,允許使用者讓第三方應用以安全且標準的方式獲取該使用者在某一網站、移動或桌面應用上儲存的私密的資源(如使用者個人資訊、照片、視訊、聯絡人列表),而無需將使用者名稱和密碼提供給第三方應用。
OAuth 2.0是OAuth協議的下一版本,但不向後相容OAuth 1.0。 OAuth 2.0關注客戶端開發者的簡易性,同時為Web應用,桌面應用和手機,和起居室裝置提供專門的認證流程。
OAuth允許使用者提供一個令牌,而不是使用者名稱和密碼來訪問他們存放在特定服務提供者的資料。每一個令牌授權一個特定的網站(例如,視訊編輯網站)在特定的時段(例如,接下來的2小時內)內訪問特定的資源(例如僅僅是某一相簿中的視訊)。這樣,OAuth允許使用者授權第三方網站訪問他們儲存在另外的服務提供者上的資訊,而不需要分享他們的訪問許可或他們資料的所有內容。
新浪微博API目前也使用OAuth 2.0。
二、微信公眾平臺OAuth2.0授權
微信公眾平臺OAuth2.0授權詳細步驟如下:
1. 使用者關注微信公眾賬號。
2. 微信公眾賬號提供使用者請求授權頁面URL。
3. 使用者點選授權頁面URL,將向伺服器發起請求
4. 伺服器詢問使用者是否同意授權給微信公眾賬號(scope為snsapi_base時無此步驟)
5. 使用者同意(scope為snsapi_base時無此步驟)
6. 伺服器將CODE通過回撥傳給微信公眾賬號
7. 微信公眾賬號獲得CODE
8. 微信公眾賬號通過CODE向伺服器請求Access Token
9. 伺服器返回Access Token和OpenID給微信公眾賬號
10. 微信公眾賬號通過Access Token向伺服器請求使用者資訊(scope為snsapi_base時無此步驟)
11. 伺服器將使用者資訊回送給微信公眾賬號(scope為snsapi_base時無此步驟)
如果使用者在微信中(Web微信除外)訪問公眾號的第三方網頁,公眾號開發者可以通過此介面獲取當前使用者基本資訊(包括暱稱、性別、城市、國家)。利用使用者資訊,可以實現體驗優化、使用者來源統計、帳號繫結、使用者身份鑑權等功能。請注意,“獲取使用者基本資訊介面是在使用者和公眾號產生訊息互動時,才能根據使用者OpenID獲取使用者基本資訊,而網頁授權的方式獲取使用者基本資訊,則無需訊息互動,只是使用者進入到公眾號的網頁,就可彈出請求使用者授權的介面,使用者授權後,就可獲得其基本資訊(此過程甚至不需要使用者已經關注公眾號。)”
微信OAuth2.0授權登入讓微信使用者使用微信身份安全登入第三方應用或網站,在微信使用者授權登入已接入微信OAuth2.0的第三方應用後,第三方可以獲取到使用者的介面呼叫憑證(access_token),通過access_token可以進行微信開放平臺授權關係介面呼叫,從而可實現獲取微信使用者基本開放資訊和幫助使用者實現基礎開放功能等。
在微信公眾號請求使用者網頁授權之前,開發者需要先到公眾平臺網站的我的服務頁中配置授權回撥域名。請注意,這裡填寫的域名不要加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鑑權。
具體而言,網頁授權流程分為四步:
-
引導使用者進入授權頁面同意授權,獲取code
-
通過code換取網頁授權access_token(與基礎支援中的access_token不同)
-
如果需要,開發者可以重新整理網頁授權access_token,避免過期
-
通過網頁授權access_token和openid獲取使用者基本資訊
第一步:使用者同意授權,獲取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引數對應的授權作用域許可權。
參考連結(請在微信客戶端中開啟此連結體驗) Scope為snsapi_base https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx520c15f417810387&redirect_uri=http%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 Scope為snsapi_userinfo 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
引數說明
引數 | 是否必須 | 說明 |
---|---|---|
appid | 是 | 公眾號的唯一標識 |
redirect_uri | 是 | 授權後重定向的回撥連結地址,請使用urlencode對連結進行處理 |
response_type | 是 | 返回型別,請填寫code |
scope | 是 | 應用授權作用域,snsapi_base (不彈出授權頁面,直接跳轉,只能獲取使用者openid),snsapi_userinfo (彈出授權頁面,可通過openid拿到暱稱、性別、所在地。並且,即使在未關注的情況下,只要使用者授權,也能獲取其資訊) |
state | 否 | 重定向後會帶上state引數,開發者可以填寫a-zA-Z0-9的引數值 |
#wechat_redirect | 是 | 無論直接開啟還是做頁面302重定向時候,必須帶此引數 |
下圖為scope等於snsapi_userinfo時的授權頁面:
使用者同意授權後
如果使用者同意授權,頁面將跳轉至 redirect_uri/?code=CODE&state=STATE。若使用者禁止授權,則重定向後不會帶上code引數,僅會帶上state引數redirect_uri?state=STATE
code說明 : code作為換取access_token的票據,每次使用者授權帶上的code將不一樣,code只能使用一次,5分鐘未被使用自動過期。
第二步:通過code換取網頁授權access_token
首先請注意,這裡通過code換取的網頁授權access_token,與基礎支援中的access_token不同。公眾號可通過下述介面來獲取網頁授權access_token。如果網頁授權的作用域為snsapi_base,則本步驟中獲取到網頁授權access_token的同時,也獲取到了openid,snsapi_base式的網頁授權流程即到此為止。
請求方法
獲取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 |
返回說明
正確時返回的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擁有較短的有效期,當access_token超時後,可以使用refresh_token進行重新整理,refresh_token擁有較長的有效期(7天、30天、60天、90天),當refresh_token失效的後,需要使用者重新授權。
請求方法
獲取第二步的refresh_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引數 |
返回說明
正確時返回的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 | 使用者唯一標識 |
scope | 使用者授權的作用域,使用逗號(,)分隔 |
錯誤時微信會返回JSON資料包如下(示例為Code無效錯誤):
{"errcode":40029,"errmsg":"invalid code"}
第四步:拉取使用者資訊(需scope為 snsapi_userinfo)
如果網頁授權作用域為snsapi_userinfo,則此時開發者可以通過access_token和openid拉取使用者資訊了。
請求方法
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 | 使用者的唯一標識 |
lang | 返回國家地區語言版本,zh_CN 簡體,zh_TW 繁體,en 英語 |
返回說明
正確時返回的JSON資料包如下:
{ "openid":" OPENID", " nickname": NICKNAME, "sex":"1", "province":"PROVINCE" "city":"CITY", "country":"COUNTRY", "headimgurl": "http://wx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/46", "privilege":[ "PRIVILEGE1" "PRIVILEGE2" ] }
引數 | 描述 |
---|---|
openid | 使用者的唯一標識 |
nickname | 使用者暱稱 |
sex | 使用者的性別,值為1時是男性,值為2時是女性,值為0時是未知 |
province | 使用者個人資料填寫的省份 |
city | 普通使用者個人資料填寫的城市 |
country | 國家,如中國為CN |
headimgurl | 使用者頭像,最後一個數值代表正方形頭像大小(有0、46、64、96、132數值可選,0代表640*640正方形頭像),使用者沒有頭像時該項為空 |
privilege | 使用者特權資訊,json 陣列,如微信沃卡使用者為(chinaunicom) |
錯誤時微信會返回JSON資料包如下(示例為openid無效):
{"errcode":40003,"errmsg":" invalid openid "}
附:檢驗授權憑證(access_token)是否有效
請求方法
http:GET(請使用https協議) https://api.weixin.qq.com/sns/auth?access_token=ACCESS_TOKEN&openid=OPENID
引數說明
引數 | 描述 |
---|---|
access_token | 網頁授權介面呼叫憑證,注意:此access_token與基礎支援的access_token不同 |
openid | 使用者的唯一標識 |
返回說明
正確的Json返回結果:
{ "errcode":0,"errmsg":"ok"}
錯誤時的Json返回示例:
{ "errcode":40003,"errmsg":"invalid openid"}
案例程式碼:
請求授權頁面的構造方式
https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
前端程式碼
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd";><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><meta name="viewport" content="width=device-width,height=device-height,inital-scale=1.0,maximum-scale=1.0,user-scalable=no;"><meta name="apple-mobile-web-app-capable" content="yes"><meta name="apple-mobile-web-app-status-bar-style" content="black"><meta name="format-detection" content="telephone=no"><title>會員註冊</title><script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript">
function callback(result) {
alert('cucess');
alert(result); //輸出openid
}
function getQueryString(name) {
var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");
var r = window.location.search.substr(1).match(reg);
if (r != null) return unescape(r[2]); return null;
}
var code = getQueryString("code");
$.ajax({
async: false, url: "http://atest.sinaapp.com/oauth2.php", //這是我的服務端處理檔案php的
type: "GET", //下面幾行是jsoup,如果去掉下面幾行的註釋,後端對應的返回結果也要去掉註釋
// dataType: 'jsonp',
// jsonp: 'callback', //jsonp的值自定義,如果使用jsoncallback,那麼伺服器端,要返回一個jsoncallback的值對應的物件.
// jsonpCallback:'callback',
data: {code:code}, //傳遞本頁面獲取的code到後臺,以便後臺獲取openid
timeout: 5000,
success: function (result) {
callback(result);
},
error: function (jqXHR, textStatus, errorThrown) {
alert(textStatus); }
});
</script>
</head><body></body>
後端程式碼
<?php
$code = $_GET['code'];//前端傳來的code值
$appid = "wx468622291a1e99d6";
$appsecret = "98566dc38863aa4395fabebb0de6ecc1";//獲取openid
$url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=$appid&secret=$appsecret&code=$code&grant_type=authorization_code";
$result = https_request($url);
$jsoninfo = json_decode($result, true);
$openid = $jsoninfo["openid"];//從返回json結果中讀出openid
$access_token = $jsoninfo["access_token"];//從返回json結果中讀出openid
$callback=$_GET['callback']; // echo $callback."({result:'".$openid."'})";
$url1 = "https://api.weixin.qq.com/sns/userinfo?access_token=$access_token&openid=$openid&lang=zh_CN";
$result1 = https_request($url1);
$jsoninfo1 = json_decode($result1, true);
$nickname=$jsoninfo1["nickname"];
echo $openid.":".$access_token.":".$nickname; //把openid 送回前端
function https_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, 1);
$output = curl_exec($curl);
curl_close($curl);
return $output;
}
?>