http://oauth.net/2/ 協議的原文。原來是1.0版本,如今是2.0版本了php
html
https://ruby-china.org/topics/15396
https://blog.yorkxin.org/posts/2013/09/30/oauth2-1-introduction/
通俗解釋:git
http://www.ruanyifeng.com/blog/2014/05/oauth_2_0.htmlgithub
要解決的問題:算法
獲取受權。每次登陸,都要讓用戶進行受權。數據庫
現實中的例子,只有用戶贊成受權給媽媽網,騰訊才發放一個令牌給媽媽網,媽媽網憑藉這個令牌去騰訊獲取用戶的信息。json
那麼就意味着說,令牌的生成規則要跟用戶和媽媽網的信息綁定關係。瀏覽器
奇怪,若是這個令牌被泄漏呢?別人也能夠憑藉這個令牌拿到信息啊。現實生活中,別人即使拿到你的令牌(票券),的確是能夠去通行。緩存
可是現實生活中發現了這個漏洞後,會增長一些安排判斷,好比車票,別人就算偷到,撿到車票也不能去乘車,還要比對一下是否與身份證號碼匹配。安全
除非你拿到對方的身份證了。這樣把安全係數提升。發生的機率就會減小。就算你拿到對方的身份證,有時候還會看看你本人樣子是否與身份證照片相差很大。
在咱們這一層,你在url中是能夠看到key,沒錯。可是你得同時拿到密鑰才行。須要密鑰對數據進行簽名的。簽名失敗是不容許訪問的。
騰訊的微信是這樣子:
一、用戶受權後,則生成一個臨時性的code返回給客戶端
code如何生成的呢?參考了oauth2.0協議
該碼與客戶端ID和重定向URI,是一一對應關係。
客戶端id。重定向的uri,是早就預約義好了。
請求騰訊去獲取code的時候,會帶兩個關鍵性的參數:騰訊的appid(就是oauth2.0協議中的客戶端id)、redirect_uri(騰訊要回跳回來的地址)
如今思考:爲何要驗證redirect_uri是否與後臺填寫的域名一致呢。其實這樣能夠增長安全性。
我只會重定向到指定的url去。這樣會更加安全。不會重定向到攻擊者指定的url去。
qq登陸的時候,還爲了更加安全,作全路徑判斷了。之前只是同一個域名下便可了。後來爲了安全。必須後臺填寫徹底相同的url地址。
好比後臺配置必須是這樣的完整url: www.abc.com/qqlogin/callback.php
是域名www.abc.com是不行,之前是能夠的。
那麼會徹底驗證這個url是否一致。不然就拒絕掉。
這對於passport的參考意義:全部接入passport的子應用,我是否是能夠限制回調地址呢?限制在指定域名下就能夠。
目前來看,還不須要這樣子作。沒有遇到問題?
二、憑藉appid和臨時性的code去獲取access_token
三、憑藉access_token和用戶的openid去獲取用戶的信息(暱稱,頭像等等)
通俗例子:
如今想要實現qq登陸。
一種辦法是:讓用戶把對方的賬號和密碼發給a網站,讓a網站去登陸qq。那這樣就不安全了,由於密碼不能泄漏給這些網站。
把賬號和密碼直接給a網站,a網站就能獲取到qq的全部信息的權力了。這樣子不安全。
如今明白緣由了,爲何要設計一個用戶的access_token,在每一個網站不一樣。就是爲了安全性。假設一個用戶的access_token在a網站是同樣的,在b網站也是同樣的。
那麼,泄漏了,就麻煩了。由於我能夠獲取用戶的全部資料了。
這個access_token能夠理解成令牌。
我在思考,我應該如何設計這種模式呢?
我能夠畫序列圖,這樣子清楚解釋。
關鍵是這個access_token,這樣子應用就不須要獲取用戶的密碼了。徹底經過這個受權層來實現登陸。
我以爲code 與access_token是創建了一個映射關係的。
access_token則是與用戶的openid創建了映射關係的。
access_token openid(根據appid和qq進行生成)
其實我在返回ticket的時候,徹底能夠增長一個字段expire,表示過時時間。這樣子他們本身能夠根據去刷新本身的cookie時長?
子應用和passport系統登陸時間不一致,的確會致使一些用戶體驗很差。
靠近你們的習慣。oauth2.0這樣的模式去。
獲取臨時性的code。而後憑藉code獲取ticket(相似於access_token)。
每次請求都必需要帶上passport授予的key在url中。
思考:qq,微信這些實現oauth2.0登陸的時候,爲何除了帶上screct還要帶上appid呢?
微信登陸,只須要帶上appid,就能夠訪問微信了。關於安全性,不過最終都要通過用戶的受權:用戶的微信賬號必須是登陸狀態。即使是登陸狀態,也要通過用戶受權訪問。
一、跳轉到微信的受權登陸頁面去,不須要screct。由於這個須要用戶受權才能操做。不涉及到安全性。之因此要傳遞一個appid在url中給微信,微信能夠知道用戶要登陸哪一個應用而已,方便作提醒"你正在準備登陸媽媽網"
二、經過code去獲取access_token,須要screct的緣由是,這裏涉及到安全性了。
爲何要設計一個refresh token?
怕access_token過時。
爲何要增長這個refresh token去延長access_token的有效期呢?
客戶端:指的就是第三方應用程序。好比網站。
服務商:如何理解呢?通俗點理解呢。
資源全部者:指用戶。這些資源是用戶的,好比我的信息,保存的資料都是用戶的。
state | 否 | 用於保持請求和回調的狀態,受權請求後原樣帶回給第三方。該參數可用於防止csrf攻擊(跨站請求僞造攻擊),建議第三方帶上該參數,可設置爲簡單的隨機數加session進行校驗 |
這個state指是能夠網站本身設置的參數,qq那邊只是原封不動的返回來。聽說這樣能夠避免csrf攻擊。
不太理解。可是能夠模仿。oauth官網文檔是推薦填寫這個的。既然是爲了不csrf攻擊,僞造請求。
那麼state的值就不要是一個固定的值了,由於能夠僞造。因此要設置成一個動態變化的值。
好比能夠:時間戳+隨機數。時間戳是能夠僞造的(用其餘語言生成一個,時間只要同步就能夠)。可是加上隨機數。就很難肯定是哪一個隨機數了。由於隨機數每次都是變化的,對方就算模擬也很難模擬出剛好生成同一個隨機數出來,它是在一個範圍內變化的。
思考:爲何單獨只須要在瀏覽器重定向(好比騰訊回跳到本身網站)的時候,附加上state返回呢?
其餘經過access_token獲取用戶信息,這些都是服務器之間的通訊。很難被截取到。
可是獲取臨時性code這一步,是在瀏覽器回跳的時候,別人也能夠重定向這個地址,僞造請求。
如今要加上一個每次都變化的值會比較安全點。究竟是如何攻擊的呢?
passport倒未必須要這樣子,我以爲passport調用方是本身的應用。不是外部應用。是本身公司的。是這樣的嗎?
我如今能夠設置一個時間戳,而後緩存在session中。qq會返回過來。若是返回來的值不同,則提示頁面已過時。
這是網頁版登陸的正式文檔:
https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&lang=zh_CN
弄錯了,結果跑到公衆賬號平臺去了:
http://mp.weixin.qq.com/wiki/17/c0f37d5704f0b64713d5d2c37b468d75.html#.E7.AC.AC.E4.B8.80.E6.AD.A5.EF.BC.9A.E7.94.A8.E6.88.B7.E5.90.8C.E6.84.8F.E6.8E.88.E6.9D.83.EF.BC.8C.E8.8E.B7.E5.8F.96code
難怪提示,必需要使用客戶端打開。
實際上過程是:二維碼。掃描後就能夠進行登陸了。
我如今想理解一下,這個openid,unionid是根據什麼生成的呢?
如何生成的呢?
同一個qq號,每一個應用id對應的openid會不一樣。
容易把人給搞暈:access_token
openid之類的。
根據access_token才能訪問。access_token存在有效期。附加上access_token和openid才能拿到指定用戶的信息。
目前騰訊分配給咱們的appid是一個特殊的appid,因爲是特殊性。在騰訊的後臺查詢不到,騰訊並無單獨提供後臺給咱們,直接修改回調地址。只能聯繫對方的技術人員修改
關於當時的背景:理解下面知識點
他們對一個用戶(qq)的openid值是根據應用的appid生成的,也就是說:QQ號12348899,換一個appid,這個qq號對應的openid值就不一樣了。
這樣子設計是爲了安全考慮。不然不一樣的應用(好比a公司和b公司的應用),只要知道一個qq號碼,就能獲取到它的openid去其餘地方使用。或者保存到本身的數據庫裏面。
如今目的要保證不同,騰訊每一個qq的openid值根據應用不一樣,而不一樣的。
媽媽網當時爲了解決這樣的問題:
因爲32論壇的域名,都是不同的一級域名,好比www.gzmama.cn、www.cdmama.cn。根據騰訊的qq機制,那麼同一個qq用戶在這些應用對應的openid值就不同了。
想實現32論壇的qq用戶,表現得是同一個openid。根據上面對騰訊openid的介紹,騰訊原來的機制沒法知足。因此咱們當時要求騰訊爲咱們單獨開設了一個appid。
此appid是一個特殊的appid。把不少的應用合在一塊兒。
贊成受權,實際上就是根據用戶的登陸信息和appid生成一個code嗎?這個code於這些信息是關聯的。
回跳回來的時候,帶這個code,憑藉這個code能夠獲取access_token
我之前覺得,獲取到access_token,獲取到code會不安全。但實際上受權的模式已經避免密碼泄漏的問題了。
對方如何才能獲取到code,code只是一個橋樑,一箇中間做用。用完一次就刪除了。
關鍵是對方怎麼攻擊呢?
咱們的目的,就是要避免攻擊者去獲取用戶的資源:照片,資料等信息。
必須經過用戶臨時受權,每受權一次才能進一步操做。
實際上能夠直接返回access_token給客戶端。可是不安全。必需要經過code來獲取。
要隱藏。在服務器之間進行通訊,這樣很難抓到包。
我只要拿到access_token,那麼也是能夠獲取用戶信息了。
請求的時候帶scope參數,這樣子受權服務器就知道這個應用打算申請什麼權限,這樣能夠提醒用戶:你將要受權進行幹嗎,你是否贊成。
在oauth2.0協議中,提供了好幾種模式。其中一種模式是直接把access_token放到url中返回給客戶端了。這種是簡化模式。存在token被泄漏的風險。
"access_token":"2YotnFZFEjr1zCsicMWpAA", "token_type":"example", "expires_in":3600, "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA", "example_parameter":"example_value"
要有訪問令牌access_token。訪問令牌有個過時時間。若是要延長,就要使用refresh_token
來進行刷新。
access_token有效期是2個小時。refresh_token有效期是30天。
在qq中,Access_Token的有效期默認是3個月,過時後須要用戶從新受權才能得到新的Access_Token。
這是php版本的 演示:
http://brentertainment.com/oauth2/lockdin/authorize?response_type=code&client_id=demoapp&redirect_uri=http%3A%2F%2Fbrentertainment.com%2Foauth2%2Fclient%2Freceive_authcode&state=6507ae4073f82d4a228eeef1a5af22d6#
https://github.com/bshaffer/oauth2-demo-php 這是官方提供的各個語言的demo
access_token與openid有什麼區別呢?完成的意義有什麼不同呢?
在oautho2.0協議原文中,只有access_token,並無openid的概念。因此openid只是在此基礎上加的一個概念。
延長令牌,其實是從新生成一個令牌: 從新生成refresh_token和access_token,先判斷這個refresh_token是否是合法就好了。
access_token和openid都要實時生成。
使用一種算法來生成。這種算法必須是可逆的。也就是根據access_token可以反解出uid出來。openid的值也是要同樣的。
使用一個密鑰來生成。
desc算法嗎?
這篇文章比較好講述了openid和access_token的區別
http://desert3.iteye.com/blog/1701626
關於access_token被盜用的問題思考
想一想現實生活中的例子,若是你撿到別人的火車票後,直接能夠去乘車,之前是沒有身份認證。我只認車票就放行。
這個動做就相似於,拿了access_token。
如今咱們的思路與車票增長驗證是同樣的思路,是增長驗證,把門檻提升。
具體這樣作:你拿到access_token還不夠。還須要傳遞密鑰來驗證才行。
就算你能偷到access_token還不夠,你還得知道密鑰才行。
如今明白access_token的有效期不是安全的關鍵因素。短一點的確是比長更加安全。
安全的核心因素是什麼呢?就是增長障礙物,門檻增長。
考慮到用code交換access_token是服務器之間的交互。code是容易被知道,可是密鑰很難知道。token交換的時候是服務器之間的通訊了。
總結:思路就是增長多幾道的驗證門檻。
access_token準確的理解應該是這樣:
是用戶對第三方應用進行受權,受權能夠在第三方應用進行登陸。好比媽媽網的用戶,能夠在掛號網站進行登陸。這須要用戶進行受權才行。
受權過的用戶會生成一個access_token,這個access_token要與應用id和用戶id進行關聯(對應關係存儲起來)
這句話理解到了本質;OAuth能夠把提供的Token,限制在一個網站特定時間段的的特定資源。
爲何經過access_token就能直接去獲取用戶的信息呢?根本不須要傳遞密鑰去。
騰訊和微博在這方面是同樣的模式。怎麼來理解呢?
難道是基於這樣一個假設:access_token不能隨便被拿到。須要門檻。因此若是你可以拿到,那就說明你是正常的用戶。實際上,我以爲若是是這樣的理解,這種理解就是不夠全面的。
把client_id和client_secret當作就是這個app訪問受權中心的賬號和密碼,這麼來理解會更加通俗點
這裏解釋了,爲何access_token不要時間太長。
短時間token和長效的身份憑據 - 原先的OAuth,會發行一個 有效期很是長的token(典型的是一年有效期或者無有效期限制),在OAuth 2.0中,server將發行一個短有效期的access token和長生命期的refresh token。
這將容許客戶端無需用戶再次操做而獲取一個新的access token,而且也限制了access token的有效期。
通俗點說,access_token是故意設置比較短的時間。而後增長一個擁有長有效期的refresh_token,來延長access_token的。
access_token的生成方式?
最好是不要在 token 字串附上這些信息,即便是 hash 過的也很差,由於這樣子就有機會能夠假造 token 。要把 token 字串視爲一個參照,服務器用這個 token 字串去查到真正的受權內容。
也就是說,access_token從安全角度來講,仍是要用數據進行存儲的。
Access Token 是一個字串,記載了特定的存取範圍 (scope) 、時效等等的資訊。
兩次的access_token:
8576C24EEA96E6AC8B035C375A47C922
8576C24EEA96E6AC8B035C375A47C922
兩次的刷新token:
5FC5A99DA4774E7E3569B8BDC1170138
5FC5A99DA4774E7E3569B8BDC1170138
B03CD9A2AF5BA4CDCEA541366EFF995E
52C78B6D6F1D10979B1ED46B5F8709A2
每一次一個code。
經過openid獲取用戶信息的接口思考
想要獲取用戶的資料,經過傳遞openid來獲取。可是還不夠。若是知道openid被泄漏了。那麼就能夠獲取用戶資料,不安全了。
因此還要增長一個門檻,要傳遞一個access_token。先驗證access_token的合法性。access_token帶有失效期。是與client_id和user_id關聯了。
若是access_token合法,就能查詢到對應的client_id和user_id的信息。
那麼user_id知道了就方便查詢哪一個用戶信息了。而且,咱們還要驗證openid的合法性。openid是根據user_id和client_id換成必定算法生成出來的。
因此查詢出的client_id和user_id,就能用算法算出openid,假設是openid_b,與傳遞過來的openid_a對比,是否一致。
不一致,就要報錯:openid錯誤。
總共兩個錯誤:access_token錯誤和openid錯誤。
思考:發現要研究,就把一些東西給研究透徹。而後本身可以回答一些關鍵性的疑惑。拋出一些問題來,才能解釋掉。好比oauth,不用輸入賬號和密碼就能夠了。覺得有個access_token就能夠。那豈不是沒輸入賬號和密碼就能拿到access_token。refresh_token完成的意義有什麼不同呢?