一、概念及場景
Oauth2.0(Open Authorization)協議是一個關于授權(authorization)的開放網絡標準,是目前應用最廣泛的標準之一。簡單講,所謂授權指的是我們通過微信、github等帳號的方式登錄比如V2EX、知乎、簡書這樣的網站或應用。目前包括github、facebook、twitter、微信、微博、QQ等社交工具都集成了Oauth2.0協議以供第三方應用程序使用,實現一個社交帳號打通所有應用。
停下來想一想,刷朋友圈的時候是不是經常遇到這樣的情況呢( ̄▽ ̄),下面我將結合自己的開發和校招經歷,分享一下在Oauth2.0的授權碼模式下進行第三方應用程序開發的過程。
二、授權的角色
1、Third-party application:第三方應用程序,即上面提到的V2EX、知乎、簡書
2、Resource Owner:資源所有者,也就是持有微信、github帳號的用戶。
3、User Agent:用戶代理,比如瀏覽器這樣的工具。
4、Authorization server:認證服務器,也就是微信、github配置的專門用來處理認證的服務器。
5、Resource server:資源服務器,即微信、github存放用戶生成的資源如帳號、頭像、昵稱等的服務器。需要注意的是它與認證服務器,可以是同一臺服務器,也可以是不同的服務器
三、授權的模式
客戶端必須得到用戶的授權(authorization grant),才能獲得用戶獲取資源比如微信頭像、昵稱等的令牌(access token)。OAuth 2.0定義了四種授權方式。
1、授權碼模式(authorization code)
2、簡化模式(implicit)
3、密碼模式(resource owner password credentials)
4、客戶端模式(client credentials)
其中,授權碼模式(authorization code)是功能最完整、流程最嚴密的授權模式。
四、授權碼(Authorization Code)模式
在開發準備階段,需要從服務提供商開發者平臺(以金數據為例)注冊,取得用以獲得授權碼(code)的授權域(授權的網址)、應用ID(client_id)和對應密鑰(client_secret),并配置我們要開發的第三方應用的回調地址(redirect_uri)、授權范圍(scope);這就相當于校招的時候網申、考核的過程。
當我們畢業參加招聘時一般會經歷下面幾個過程:
報名?---->參加筆試面試---->公司發放offer---->拿到offer后進入公司拿到工牌---->有了工牌就可以使用公司的資源
其實整個Oauth2.0的授權碼模式和這個很相似。
(1)流程示意圖:
(2)完整的過程:
第一步,帶上這些參數向認證服務器(Authorization server)發送授權請求,認證服務器收到請求,驗證參數,若成功,彈出登錄頁面或授權頁面(比如上圖的截圖),若參數不一致,彈出錯誤。這一步好比校招的時候參加面試(??ω??)
*請求參數包括應用ID(client_id)、回調地址(redirect_uri)、授權范圍(scope)、response_type(Oauth2.0為code)、狀態(state)等
第二步,資源所有者(用戶)確認授權,認證服務器攜帶授權碼(code)和狀態參數(state)返回請求到相應的回調地址(redirect_uri)。可以類比校招的時候參公司給你發了offer (°?°)?
第三步,拿到了offer后,哦不,拿到了授權碼(code),就可以向認證服務器請求令牌(access token),認證服務器會返回生成的令牌(access token)及刷新令牌時用到的(refresh token)等參數。發工牌啦 ("▔□▔)/
*請求參數包括應用ID(client_id)、對應密鑰(client_secret)、、上一步獲得的授權碼(code)、回調地址(redirect_uri)、授權模式(grant_type,這里是authorization_code)、授權范圍(scope)、上一步獲得的狀態(state)等
第四步,用戶代理(瀏覽器)攜帶令牌(access token)向資源服務器發送請求,訪問在第三方應用程序授權范圍(scope)內的資源,比如微信名稱、頭像等。拿到了工牌之后可以享受公司的資源 (⌒▽⌒)
五、那些坑
1、回調地址必須一致;
有時候我們在測試服務器時授權是正常的,在產品服務器上就不行,因為回調地址是唯一的,且嚴格一致的。
2、refresh token的過期時間問題;
因為每個令牌(access token)都是有過期時間(expires_in)的,一般默認為7200s,也就是2h,令牌過期后如果進行訪問資源,服務器會返回403(未授權)錯誤,所以令牌必須即時提前刷新。
為了避免重新獲得令牌的過程剛開始一樣復雜,Oauth2.0規定每個令牌(access token)生成時必須同時生成過期時間(expires_in)和刷新令牌(refresh token),在任意時間,使用刷新令牌(refresh token)可以向認證服務器請求生成一個新的令牌(access token),此時原有的令牌和刷新令牌失效!所以如果你的本地環境和測試服務器使用的是同一個令牌時,當本地環境提前刷新token后,將造成你的測試服務器無法繼續刷新token;
刷新token的2種方式:
1、主動式:提前存好令牌(access token)的過期時間(令牌過期時間=獲得accesstoken的時間+過期時間(expires_in)- 冗余時間t)。在服務器運行crontab定時任務, 每隔小于t的時間,檢查數據庫中所有用戶token的令牌過期時間是否大于當前時間,自動刷新;這樣的好處是保證每時每刻token都是有效的,但是對于服務器有一定負載;
2、被動式:(令牌過期時間=獲得access token的時間+過期時間(expires_in)。當要使用當前令牌(access token)時,檢查該令牌過期時間是否大于當前時間,進行刷新;這是最簡單的做法,能夠節省資源,但是有一定幾率會造成用戶體驗過慢,畢竟刷新token需要時間;不推薦被動式刷新。
以上是我在進行金數據應用中心的抽獎應用的開發過程中的一些體會,當然,目前基本上所有的框架都封裝了Oauth2.0的庫,大家只需要按照文檔使用這些庫,如果大家是Rails愛好者,給大家推薦一下Omniauth,如果大家是PHP Laravel的開發者,給大家推薦一下Laravel Socialite這個庫,當然,像金數據這樣的純api有很多復雜的請求,大家可以參考我做的集成SocialiteForJinshuju。
歡迎大家能分享更多的內容,嗶哩嗶哩 - ( ゜- ゜)つロ 乾杯~?
參考: