OAuth是一個開放協議,容許用戶讓第三方應用以安全且標準的方式獲取該用戶在某一網站上存儲的私密資源(如用戶我的信息、照片、視頻、聯繫人列表),而無須將用戶名和密碼提供給第三方應用。本文將詳細介紹OAuth協議以及在微信裏的具體實現。html
OAuth2.0協議介紹api
OAuth2.0是OAuth協議的下一版本,但不向後兼容OAuth 1.0。 OAuth 2.0關注客戶端開發者的簡易性,同時爲Web應用,桌面應用和手機,和起居室設備提供專門的認證流程。 OAuth2.0容許用戶提供一個令牌,而不是用戶名和密碼來訪問他們存放在特定服務提供者的數據。每個令牌受權一個特定的網站(例如,視頻編輯網站)在特定的時段(例如,接下來的2小時內)內訪問特定的資源(例如僅僅是某一相冊中的視頻)。這樣,OAuth容許用戶受權第三方網站訪問他們存儲在另外的服務提供者上的信息,而不須要分享他們的訪問許可或他們數據的全部內容。瀏覽器
OAuth2.0認證和受權的具體過程:安全
在Oauth2.0認證和受權的過程當中涉及的三方包括: 微信
1. 服務提供方,用戶使用服務提供方來存儲受保護的資源,如照片,視頻,聯繫人列表。 app
2. 用戶,存放在服務提供方的受保護的資源的擁有者。 ide
3. 客戶端,要訪問服務提供方資源的第三方應用,一般是網站,如提供照片打印服務的網站。在認證過程以前,客戶端要向服務提供者申請客戶端標識。 測試
使用OAuth進行認證和受權的過程以下所示: 優化
1. 用戶訪問客戶端的網站,想操做用戶存放在服務提供方的資源;網站
2. 客戶端向服務提供方請求一個臨時令牌;
3. 服務提供方驗證客戶端的身份後,授予一個臨時令牌;
4. 客戶端得到臨時令牌後,將用戶引導至服務提供方的受權頁面請求用戶受權。在這個過程當中將臨時令牌和客戶端的回調鏈接發送給服務提供方;
5. 用戶在服務提供方的網頁上輸入用戶名和密碼,而後受權該客戶端訪問所請求的資源;
6. 受權成功後,服務提供方引導用戶返回客戶端的網頁;
7. 客戶端根據臨時令牌從服務提供方那裏獲取訪問令牌;
8. 服務提供方根據臨時令牌和用戶的受權狀況授予客戶端訪問令牌;
9. 客戶端使用獲取的訪問令牌訪問存放在服務提供方上的受保護的資源。
微信網頁OAuth2.0受權:
若是用戶在微信中(Web微信除外)訪問公衆號的第三方網頁,公衆號開發者能夠經過此接口獲取當前用戶基本信息(包括暱稱、性別、城市、國家)。利用用戶信息,能夠實現體驗優化、用戶來源統計、賬號綁定、用戶身份鑑權等功能。
須要注意的是,獲取用戶基本信息接口(稍後博文會介紹到)是在用戶和公衆號產生消息交互時,才能根據用戶OpenID獲取用戶基本信息,而網頁受權的方式獲取用戶基本信息,則無需消息交互,只是用戶進入到公衆號的網頁,就可彈出請求用戶受權的界面,用戶受權後,就可得到其基本信息(此過程甚至不須要用戶已經關注公衆號。)
下面咱們將經過一個具體的例子來展現開發的詳細過程。
配置受權回調域名:
在微信公衆號請求用戶網頁受權以前,開發者須要先到公衆平臺網站的個人服務頁中配置受權回調名,須要注意的是這裏的域名不要加http://或者https://。另外,受權回調域名配置規範爲全域名,好比須要網頁受權的域名爲: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沒法進行OAuth2.0鑑權。
爲此進入到服務頁(使用正式的服務號或認證後的訂閱號後經過個人服務找到,若是是測試帳號直接在首頁便可找到)後找到OAuth2.0網頁受權,點擊右側的修改連接:
在彈出窗口裏輸入域名後點擊肯定按鈕保存:
用戶贊成受權,獲取Code:
此步驟至關於前面介紹到的OAuth2.0認證過程的第二步「客戶端向服務提供方請求一個臨時令牌」,這裏的Code便是臨時令牌,爲此能夠請求微信的OAuth2.0接口以獲取該Code,該接口的參數裏須要指定一個回調頁面URL,爲此咱們須要建立一個Apex Page,爲此登錄Force.com後找到域名,一般從中國訪問的域名是https://ap1.salesforce.com, 在瀏覽器地址欄中輸入https://ap1.salesforce.com/apex/oauth2test, 此時Force.com將提示頁面不存在,點擊「Create Page oauth2test」連接建立頁面:
建立好後的頁面以下,若是啓用了開發者模式,則頁面分爲上下兩個部分,上部分是顯示效果,下面是源代碼編輯窗口,默認Force.com會將自身的頂部導航、左側導航以及CSS樣式應用到新建立的頁面:
咱們經過在第一行里加入如下代碼告訴Force.com不要使用默認的CSS樣式,不要顯示頂部以及左側的導航欄,同時最後一個controller屬性指定了apex頁面對應的控制器類,相似於aspx頁面對應的aspx.cs類,鼠標保持在編輯欄窗口,按住Ctrl + S組合鍵便可保存編輯後的代碼:
<apex:page standardstylesheets="false" showHeader="false" sidebar="false" controller="oauth2testcontroller">
此時,應爲對應的oauth2testcontroller類並不存在,瀏覽器會報如下錯誤:
這裏點擊第二個連接「Create Apex class ‘public class oauth2testcontroller’」自動建立控制器類。留意這兩個連接的惟一區別在於」with sharing」關鍵字,這個關鍵字指定了當前類對各個對對象(至關於數據表)、字段等的訪問權限與當前登陸用戶同,若是不指定,Apex頁面將擁有對全部對象、字段的訪問權限。建立好後在下方代碼編輯欄中將多出一個控制器類Tab:
在該類中添加代碼以下:
1 public class oauth2testcontroller { 2 public String code {get; set;} 3 public oauth2testcontroller(){ 4 code = ApexPages.currentPage().getParameters().get('code'); 5 if(String.isBlank(code)){ 6 code = 'No Code'; 7 } 8 } 9 }
這段代碼中第2行定義了一個公開屬性code,第4行經過ApexPages對象得到URL中的code參數,並接着判斷是否code值是否爲空,若是爲空則提示No Code。下面咱們會看到微信受權成功回調此URL時會將code參數添加到URL中。
接下來略微修改前臺頁面,在頁面中顯示獲得的code值:
1 <apex:page standardstylesheets="false" showHeader="false" sidebar="false" controller="oauth2testcontroller"> 2 {!code} 3 </apex:page>
{!對象名}是Force.com Visualforce page裏用來顯示對象值的語法,接下來咱們須要配置該頁面可以經過公網進行訪問,爲此登錄Force.com後,進入Setup –> Develop –> Sites,點擊站點對應的Site Label標籤以下圖:
進入詳細配置頁面後找到「Site Visualforce Page」,點擊右側的Edit按鈕:
找到左側列表中的oauth2test頁面添加到右側,並保存修改:
此時便可經過http://johnson0001-developer-edition.ap1.force.com/oauth2test公網地址來訪問前面創造的頁面了。接下來咱們能夠利用微信平臺的OAuth2認證接口組拼URL並引導用戶經過微信來訪問,該接口的格式以下:
https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
若提示「該連接沒法訪問」,請檢查參數是否填寫錯誤,是否擁有scope參數對應的受權做用域權限,其中每一個參數的詳細說明以下:
在咱們的例子裏URL以下,其中scope咱們指定爲snsapi_userinfo,彈出受權頁面:
興許是測試帳號的關係,雖然微信接口文檔裏提到在制定scope爲snsapi_userinfo的狀況下會彈出以下圖左所示的受權頁面,但反覆嘗試(乃至刪除並從新關注帳號)中也沒有看到該頁面,不太重點是咱們獲得了臨時令牌,以下圖右所示。右圖實際是http://johnson0001-developer-edition.ap1.force.com/oauth2test頁面,用戶贊成受權後跳轉到(或者我遇到的實際狀況是直接跳轉)到redirect_uri/?CODE&state=STATE。若用戶禁止受權,則重定向後不會帶上code參數,僅會帶上state參數redirect_uri?state=STATE。
另外特別須要說明的是,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
這裏的CODE即爲經過前面方式得到的臨時令牌(票據),參數的具體說明以下:
將URL直接輸入到瀏覽器地址欄便可獲得返回數據,固然真實場景裏更多經過後臺代碼來請求,正確返回時的JSON數據包以下:
1 { 2 "access_token":"ACCESS_TOKEN", 3 "expires_in":7200, 4 "refresh_token":"REFRESH_TOKEN", 5 "openid":"OPENID", 6 "scope":"SCOPE" 7 }
參數的具體說明以下:
錯誤時微信會返回JSON數據包以下(示例爲Code無效錯誤):
{"errcode":40029,"errmsg":"invalid code"}
在本例中得到的access_token實例以下:
{"access_token":"OezXcEiiBSKSxW0eoylIeMEUA_AZuBDY8AO0IIw270MMsvemqLvgx1HqemeXIZfzXW2d6yHCPy9cA1yHZ1jHCkwlH5Ct5Jfa1jOQm88M9LzU_O8BCKMNhN7yLlHJfOFLuf4lLTNGOOsoWYxQzYVNGw","expires_in":7200,"refresh_token":"OezXcEiiBSKSxW0eoylIeMEUA_AZuBDY8AO0IIw270MMsvemqLvgx1HqemeXIZfz_Vj5pJZlv2V5wK9EzWmxQmM07cqIAwMXOdqzlQs-NY4hiyENP4WhO4Twpko-3iY_pAPZRnGGmAVt3DirZaWIyg","openid":"ou-37t936RNZEcW0mI75RN2pdxkc","scope":"snsapi_userinfo"}
能夠看到上面access_token的默認失效時間是7200秒,也就是2小時,當access_token超時後,能夠經過refresh_token進行刷新,refresh_token擁有較長的有效期(7天、30天、60天、90天),當refresh_token失效後,須要用戶從新受權,簡化理解起見,咱們在本文的最後再介紹相關技術。
拉取用戶信息(需Scope爲snasapi_userinfo):
經過access_token獲取用戶信息的接口以下,使用GET方法:
https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN
參數具體說明以下:
本例的URL以下:
輸入瀏覽器訪問便可獲得相應的用戶信息:
1 {"openid":"ou-37t936RNZEcW0mI75RN2pdxkc","nickname":"王浩","sex":1,"language":"zh_CN","city":"松江","province":"上海","country":"中國","headimgurl":"http:\/\/wx.qlogo.cn\/mmopen\/lqsZNvDqcXe8nBKHBPsp9YHuZXPtkzOD1uq3r3xxDicuDLKGlicNd1b371ODnn9xNBB9y9ChBSfL7tuX6m9FS8koY9Ex1iaJRDI\/0","privilege":[]}
刷新access_token:
能夠經過前面在「經過Code換取網頁受權access_token」小節中得到的refresh_token來調用刷新Token接口獲取更新的access_token,微信在API文檔裏介紹refresh_token擁有較長的有效期(7天、30天、60天、90天),但實際微信的refresh_token的有效期是多長沒有具體說明,若是有具體經驗的朋友歡迎分享。微信刷新access_token的接口以下:
https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=APPID&grant_type=refresh_token&refresh_token=REFRESH_TOKEN
接口的具體參數定義以下:
正確時返回的JSON數據包以下:
1 { 2 "access_token":"ACCESS_TOKEN", 3 "expires_in":7200, 4 "refresh_token":"REFRESH_TOKEN", 5 "openid":"OPENID", 6 "scope":"SCOPE" 7 }
數據包的具體定義以下:
錯誤時微信會返回JSON數據包以下(示例爲Code無效錯誤):
{"errcode":40029,"errmsg":"invalid code"}