第1、OAuth2.0
OAuth(開放受權)是一個開放標準,容許用戶讓第三方應用訪問該用戶在某一網站上存儲的私密的資源(如照片,視頻,聯繫人列表),而無需將用戶名和密碼提供給第三方應用。
容許用戶提供一個令牌,而不是用戶名和密碼來訪問他們存放在特定服務提供者的數據。每個令牌受權一個特定的網站(例如,視頻編輯網站)在特定的時段(例如,接下來的2小時內)內訪問特定的資源(例如僅僅是某一相冊中的視頻)。這樣,OAuth容許用戶受權第三方網站訪問他們存儲在另外的服務提供者上的信息,而不須要分享他們的訪問許可或他們數據的全部內容。
第2、目標
咱們這裏主要模擬使用OAuth2.0,用戶經過掃描咱們網頁應用的二維碼並進行受權登陸來獲取用戶的基本信息的過程。詳細的接口相關信息能夠在微信開放平臺上查看:https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&lang=zh_CN
第3、前期準備(獲取微信開發者權限)
咱們這裏主要講的是網站(Web)應用,網站應用微信登陸是基於OAuth2.0協議標準構建的微信OAuth2.0受權登陸系統(即上面的協議)。在微信客戶端受權登陸(獲取用戶信息)的能夠查看:http://www.cnblogs.com/0201zcr/p/5131602.html
在進行微信OAuth2.在進行微信OAuth2.0受權登陸接入以前,在微信開放平臺註冊開發者賬號,並擁有一個已審覈經過的網站應用,並得到相應的AppID和AppSecret,申請微信登陸且經過審覈後,可開始接入流程。php
填寫事後,還有有一個頁面須要填寫,提交一份紙質版申請書掃描件(會提供模板,咱們下載再來填寫後,需蓋章,簽名),配置回調域名(掃碼登陸後會跳轉的頁面)等。
以後提交審覈便可,等微信審覈經過,咱們便可得到咱們須要的網頁應用的appid和AppSecret,並配置後回調的域名了(這三樣是咱們開發所必須的)。
css
四、受權流程說明html
微信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進行接口調用,獲取用戶基本數據資源或幫助用戶實現基本操做。
json
獲取access_token時序圖:api
五、獲取網頁的二維碼瀏覽器
當咱們經過微信的認證,獲取到了appid和AppSecret,並配置了回調的域名。咱們就已經能夠獲取屬於咱們網頁的二維碼了,獲取的方式很簡單,只需打開一個微信的連接,加上咱們的appid和回調域名便可在網頁上面打開二維碼,用戶用微信客戶端掃碼並受權登陸以後即會跳轉到咱們配置的回調域名下。
注意:
一、這裏填寫的是域名(是一個字符串),而不是URL,所以請勿加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鑑權
服務器
5.一、請求url說明微信
第三方使用網站應用受權登陸前請注意已獲取相應網頁受權做用域(scope=snsapi_login),則能夠經過在PC端打開如下連接:微信開發
https://open.weixin.qq.com/connect/qrconnect?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
返回說明
用戶容許受權後,將會重定向到redirect_uri的網址上,而且帶上code和state參數
redirect_uri?code=CODE&state=STATE若用戶禁止受權,則重定向後不會帶上code參數,僅會帶上state參數
redirect_uri?state=STATE
生成二維碼代碼
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>微信掃碼登陸</title> </head> <body> <div id="login_container"></div> </body> <script src="http://res.wx.qq.com/connect/zh_CN/htmledition/js/wxLogin.js"></script> <input type="hidden" value="{$url}" id="url"> {include file="public/css"} {include file="public/js"} <script> var url=$("#url").val(); var obj = new WxLogin({ id:"login_container", //div的id appid: "wx84654355186541351", scope: "snsapi_login", redirect_uri: "http"+url, //回調地址 state: "", //參數,可帶可不帶 style: "", //樣式 提供"black"、"white"可選,默認爲黑色文字描述 href: "" //自定義樣式連接,第三方可根據實際需求覆蓋默認樣式。 });</script> </html>
注意WxLogin方法在這個文件裏:
<script src="http://res.wx.qq.com/connect/zh_CN/htmledition/js/wxLogin.js"></script>
!function(a,b,c){ function d(a){ var c="default"; a.self_redirect===!0?c="true":a.self_redirect===!1&&(c="false"); var d=b.createElement("iframe"), e="https://open.weixin.qq.com/connect/qrconnect?appid="+a.appid+"&scope="+a.scope+"&redirect_uri="+a.redirect_uri+"&state="+a.state+"&login_type=jssdk&self_redirect="+c; e+=a.style?"&style="+a.style:"", e+=a.href?"&href="+a.href:"", d.src=e, d.frameBorder="0", d.allowTransparency="true", d.scrolling="no", d.width="300px", d.height="400px"; var f=b.getElementById(a.id); f.innerHTML="", f.appendChild(d) }a.WxLogin=d}(window,document);
5.二、事例1:
一號店的微信二維碼連接以下:
https://open.weixin.qq.com/connect/qrconnect?appid=wxbdc5610cc59c1631&redirect_uri=https%3A%2F%2Fpassport.yhd.com%2Fwechat%2Fcallback.do&response_type=code&scope=snsapi_login&state=3d6be0a4035d839573b04816624a415e#wechat_redirect
將其複製到瀏覽器中打開便可得到一號店的二維碼,二維碼頁面以下:
經過使用微信客戶端的掃一掃功能,掃描該二維碼,即會跳轉到上面填寫redirect_uri所在的地址上。假如用戶贊成受權,這裏就得到了微信返回的code參數了。
六、獲取用戶信息
假如前面已經得到code。咱們能夠經過code參數去獲取用戶openid和access_token,進而得到用戶的信息。
6.一、經過code參數獲取access_token
https://api.weixin.qq.com/sns/oauth2/access_token?
appid=APPID
&secret=SECRET
&code=CODE
&grant_type=authorization_code
正確的返回:
{
"access_token":"ACCESS_TOKEN",
"expires_in":7200,
"refresh_token":"REFRESH_TOKEN",
"openid":"OPENID",
"scope":"SCOPE",
"unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"
}
錯誤返回樣例:{"errcode":40029,"errmsg":"invalid code"}
6.二、經過access_token獲取用戶的基本信息
access_token有效且爲超時;
微信用戶已受權給第三方應用帳號相應接口做用域(scope)【在二維碼生成鏈接那裏填寫】
使用snsapi_base做用域的受權是掃碼以後無需用戶點擊受權,掃碼後直接跳轉,用戶感受不到受權了,但這種受權方式能獲取的數據量有限,這裏咱們要獲取用戶的基本信息,咱們須要使用snsapi_userinfo受權。使用snsapi_userinfo受權,掃碼後出現相似於下面的受權界面
此接口用於獲取用戶我的信息。開發者可經過OpenID來獲取用戶基本信息。特別須要注意的是,若是開發者擁有多個移動應用、網站應用和公衆賬號,可經過獲取用戶基本信息中的unionid來區分用戶的惟一性,由於只要是同一個微信開放平臺賬號下的移動應用、網站應用和公衆賬號,用戶的unionid是惟一的。換句話說,同一用戶,對同一個微信開放平臺下的不一樣應用,unionid是相同的。請注意,在用戶修改微信頭像後,舊的微信頭像URL將會失效,所以開發者應該本身在獲取用戶信息後,將頭像圖片保存下來,避免微信頭像URL失效後的異常狀況。https://api.weixin.qq.com/sns/userinfo?
access_token=ACCESS_TOKEN
&openid=OPENID
正確的Json返回結果:
{
"openid":"OPENID",
"nickname":"NICKNAME",
"sex":1,
"province":"PROVINCE",
"city":"CITY",
"country":"COUNTRY",
"headimgurl": "http://wx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/0",
"privilege":[
"PRIVILEGE1",
"PRIVILEGE2"
],
"unionid": " o6_bmasdasdsad6_2sgVt7hMZOPfL"
}
七、總結
最近着手開發了微信網頁掃碼登陸和公衆號受權登陸,二者的開發很相似。
二者均可以經過微信客戶端掃碼受權的方式,讓第三方頁面得到微信用戶的一些基本信息(暱稱、性別、所在地、在微信惟一標示等……)。他們都是經過提供一個連接讓用戶受權的方式。但網頁版須要在頁面打開二維碼以後受權,而公衆號則須要用戶先關注了咱們的公衆號,而後點開公衆號裏面的連接,確認受權便可。
網頁掃碼登陸須要將受權的連接(二維碼連接)在網頁中打開、而公衆號受權登陸的連接必需要微信客戶端中打開。
不管網頁掃碼登陸仍是在公衆號中受權登陸,都是經過受權的方式得到一個code參數,以後經過code參數獲取access_token和openid和經過access_token和openid去獲取用戶的基本信息的請求連接是同樣的。
八、在php使用該功能能夠封裝一個公共的類class_weixin_adv,在這裏主要用到的是curl擴展,代碼以下:
1 <?php 2 /** 3 * 微信SDK 4 * pan041ymail@gmail.com 5 */ 6 class class_weixin_adv 7 { 8 var $appid = ""; 9 var $appsecret = ""; 10 //構造函數,獲取Access Token 11 public function __construct($appid = NULL, $appsecret = NULL) 12 { 13 if($appid){ 14 $this->appid = $appid; 15 } 16 if($appsecret){ 17 $this->appsecret = $appsecret; 18 } 19 $this->lasttime = 1395049256; 20 $this->access_token = "nRZvVpDU7LxcSi7GnG2LrUcmKbAECzRf0NyDBwKlng4nMPf88d34pkzdNcvhqm4clidLGAS18cN1RTSK60p49zIZY4aO13sF-eqsCs0xjlbad-lKVskk8T7gALQ5dIrgXbQQ_TAesSasjJ210vIqTQ"; 21 if (time() > ($this->lasttime + 7200)){ 22 $url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=".$this->appid."&secret=".$this->appsecret; 23 $res = $this->https_request($url); 24 $result = json_decode($res, true); 25 $this->access_token = $result["access_token"]; 26 $this->lasttime = time(); 27 } 28 } 29 //獲取用戶基本信息 30 public function get_user_info($openid) 31 { 32 $url = "https://api.weixin.qq.com/sns/userinfo?access_token={$this->access_token}&openid={$openid}&lang=zh_CN"; 33 $res = $this->https_request($url); 34 return json_decode($res, true); 35 } 36 //https請求 37 public function https_request($url, $data = null) 38 { 39 $curl = curl_init(); 40 curl_setopt($curl, CURLOPT_URL, $url); 41 curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE); 42 curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE); 43 if (!empty($data)){ 44 curl_setopt($curl, CURLOPT_POST, 1); 45 curl_setopt($curl, CURLOPT_POSTFIELDS, $data); 46 } 47 curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); 48 $output = curl_exec($curl); 49 curl_close($curl); 50 return $output; 51 } 52 }
在咱們須要用的方法裏引入這個類,在這裏本人使用該類的get_user_info的方法他會報錯緣由多是在使用該方法時,又重新走了一遍該類的構造方法因此在獲取用戶的我的信息時沒有用他類裏面的方法,代碼以下:
1 function oauth2(){ 2 include('./class_weixin_adv.php'); 3 $appid=""; 4 $secret=""; 5 $weixin=new class_weixin_adv($appid, $secret); 6 if (isset($_GET['code'])){ 7 $url="https://api.weixin.qq.com/sns/oauth2/access_token?appid={$appid}&secret={$secret}&code={$_GET['code']}&grant_type=authorization_code"; 8 $res = $weixin->https_request($url); 9 $res=(json_decode($res, true)); 10 11 // $row=$weixin->get_user_info($res['openid']); 12 13 $url = "https://api.weixin.qq.com/sns/userinfo?access_token={$res['access_token']}&openid={$res['openid']}&lang=zh_CN"; 14 $res =https_request($url); 15 $res=json_decode($res, true); 16 if ($res['openid']) { 17 //用戶的我的信息獲取成功,咱們能夠進行下一步操做,$res是用戶的我的信息 18 return $res; 19 }else{ 20 return ('受權出錯,請從新受權!'); 21 } 22 }else{ 23 return "NO CODE"; 24 } 25 } 26 //https請求 27 function https_request($url, $data = null) 28 { 29 $curl = curl_init(); 30 curl_setopt($curl, CURLOPT_URL, $url); 31 curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE); 32 curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE); 33 if (!empty($data)){ 34 curl_setopt($curl, CURLOPT_POST, 1); 35 curl_setopt($curl, CURLOPT_POSTFIELDS, $data); 36 } 37 curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); 38 $output = curl_exec($curl); 39 curl_close($curl); 40 return $output; 41 }
9、以上程序若是在本地測試須要將本地的服務器映射到外網上不然微信的服務器不能成功回調到你的服務器上,因此這個時候咱們須要下載ngrok,下載地址 :https://ngrok.com/
下載成功以後我就能夠解壓,以下
一、咱們在doc命令中找到ngrok.exe的文件夾
二、在執行ngrok http 80 的命令就會出現
,我在測試的時候,這個地址連接不穩,有時候連不上,(建議將電腦的防火牆關閉)。