1. 程式人生 > >深入理解基於OAuth2.0&第三方登入之GitHub實踐

深入理解基於OAuth2.0&第三方登入之GitHub實踐

基於OAuth2.0的第三方登入

第三方登入的實質

第三方登入的實質,就是在OAuth2.0協議的基礎上,利用外部的標識來獲取帳號的內部標識然後完成登入的過程。 具體的講,就是將三方的帳號繫結到產品自身的帳號上,當查詢到使用者第三方的帳號已經綁定了平臺的某個user_id時,直接登入對應的帳號。例如利用微信QQ快捷登陸,可以不用註冊APP賬號,先點選跳轉到微信,再點選授權進去APP中。

幾個重要概念

1)外部標識 用來使用使用者身份的標誌,可以是使用者名稱,手機號,郵箱等,每一個外部標識一定和一個內部標識相關聯用以確定一個使用者。 外部標識的作用有兩個

  1. 讓使用者通過自己熟知且佔有的外部標識來登入產品
  2. 可以通過校驗外部標識來實現找回或轉移資料資產

2)內部標識 即產品中用於標識使用者唯一性的標誌,例如user_id,必須有,不可更改且唯一,使用者一般接觸不到內部標識。 當一個內部標識建立後,使用者所有的資料資產都會繫結到這個內部標識上。

3)user_id 一個常用的內部標識,類似你的18位身份證ID

4)app_id 用於區別不同APP的ID,具有唯一性。

5)open_id 第三方平臺為了使用者資訊的安全,一般不會直接將使用者的內部標識給到其他產品,而是選擇了給一個外部標識,這個open_id就是微信給各個APP用以區分微信使用者身份的外部標識。

6)union_id 不同的產品的可以使用同一個union_id來確認使用者的身份。

7)access_token 可以理解為通行證,有了這個通行證,就能獲取到第三方平臺指定使用者的有限資訊。

8)OAuth 2.0 OAuth2.0就是客戶端和認證伺服器之間由於相互不信任而產生的一個授權協議,只要授權方和被授權方遵守這個協議去寫程式碼提供服務,那雙方就是實現了OAuth2.0模式。

為什麼需要加入第三方登入

  1. 提高登入轉化率,登入更加快捷,不需要輸入密碼
  2. 提高註冊轉化率,註冊更加快速,方便獲取使用者資訊
  3. 信賴感(讓使用者覺得這個產品和大廠是有合作的,提高對產品的信賴感)

OAuth2.0協議規範流程

在這裡插入圖片描述 (1) Client請求RO的授權,請求中一般包含:要訪問的資源路徑,操作型別,Client的身份等資訊。 (2) RO批准授權,並將“授權證據”傳送給Client。至於RO如何批准,這個是協議之外的事情。典型的做法是,AS提供授權審批介面,讓RO顯式批准。這個可以參考下一節例項化分析中的描述。 (3) Client向AS請求“訪問令牌(Access Token)”。此時,Client需向AS提供RO的“授權證據”,以及Client自己身份的憑證。 (4) AS驗證通過後,向Client返回“訪問令牌”。訪問令牌也有多種型別,若為bearer型別,那麼誰持有訪問令牌,誰就能訪問資源。 (5) Client攜帶“訪問令牌”訪問RS上的資源。在令牌的有效期內,Client可以多次攜帶令牌去訪問資源。 (6) RS驗證令牌的有效性,比如是否偽造、是否越權、是否過期,驗證通過後,才能提供服務。

最典型的Authorization Code 授權模式

在這裡插入圖片描述 核心思想: oauth 的核心思想就是要讓第三方在不知道使用者名稱密碼的情況下完成鑑權,但是沒有密碼使用者名稱組合根本不可能有效鑑權, oauth 實際的過程是一個李代桃疆的手法。在第一方用你的原始使用者名稱和密碼組合,生成另外一對名稱密碼組合,這個階段叫做獲取 code 和 state,這對組合送到第二方也就是你的資源所在地,同樣較驗一遍,如果合格,給你生成一個帶有時效性的 access token, 第三方在有效期內拿著這個 access token 跳過第一方直接請求第二方的資源,至於為什麼不直接返回 access token? 是因為如果使用 code 方式的話,伺服器獲得使用者授權後通過 302 跳轉到你的 callback URI 上,並在 url query 上帶上用於交換 accesd token 的 code ,你在瀏覽器位址列就可以看到這個code ,已經暴露有可能被不法應用,所以在 url 上直接返回 access token 是不安全的,而client拿到code以後換取access token是client後臺對認證伺服器的訪問,並且需要clientID和client secret,不依賴瀏覽器,access token不會暴露出去。

為何引入authorization_code?

因為單從OAuth2.0的授權過程來看,如果直接返回access_token,協議將變得更加簡潔,而且少一次Client與AS之間的互動,效能也更優,其實不然。引入authorization_code有很多妙處,主要原因如下:

  1. 瀏覽器的redirect_uri是一個不安全通道,此方式不適合於傳遞敏感資料(如access_token),會顯著擴大access_token被洩露的風險。 但authorization_code可以通過redirect_uri方式來傳遞,是因為authorization_code並不像access_token一樣敏感。 即使authorization_code被洩露,攻擊者也無法直接拿到access_token,因為拿authorization_code去交換access_token是需要驗證Client的真實身份。

  2. 由於協議需要驗證Client的身份,如果不引入authorization_code,這個Client的身份認證只能通過第1步的redirect_uri來傳遞。同樣由於redirect_uri是一個不安全通道,這就額外要求Client必須使用數字簽名技術來進行身份認證,而不能用簡單的密碼或口令認證方式。 引入authorization_code之後,AS可以直接對Client進行身份認證(見步驟4和5),而且可以支援任意的Client認證方式(比如,簡單地直接將Client端金鑰傳送給AS)。

OAuth 協議設計不同於簡單的網路安全協議的設計,因為OAuth需要考慮各種Web攻擊,比如CSRF (Cross-Site Request Forgery), XSS (Cross Site Script), Clickjacking。 在redirect_uri中引入state引數就是從瀏覽器安全形度考慮的,有了它就可以抵制CSRF攻擊。

第三方登入之GitHub實踐

開發之前,需要前往第三方登入的開發者平臺QQ、新浪微博、Github,註冊賬號並填寫資訊申請接入,成功後會給你一個ID和祕鑰,以後你就通過該ID和祕鑰來獲取令牌,從而實現第三方登入。申請ID和祕鑰時Github不需要稽核,所以本文主要介紹GitHub實踐。QQ、微信、微博等需要稽核,但流程和原理都是一樣的。

Register a new OAuth application

登陸個人GitHub賬號,進入【Settings】->選擇【applications】->選擇【Developer applications】-> 【Register a new OAuth application】

填寫必要資訊

  • Application name--應用名稱
  • Application description--應用描述
  • Authorization callback URL--後端回撥url http://localhost:8888/login/oauth2/code 這是最重要的一環,因為github那邊回撥會傳你一個code引數

註冊之後會得到 github提供的client id和client secret

現在,我們需要做下列事情:

  • 在首頁顯示Github的授權連結,使使用者能夠訪問authorizationUrl
  • 編寫一個Controller,處理http://localhost:8888/oauth/github/callback?code={code}&state={state}的請求,主要是拿到code
  • 用code訪問http://localhost:8888/oauth/github/callback?code={code}&state={state}access token
  • 然後利用access token訪問https://api.github.com/user?access_token={access_token},拿到使用者資訊

引入必要的依賴,就可以開發了,前期程式碼寫的有些繁瑣,後來發現巧妙使用配置檔案application.yml中會更加簡潔,因為Spring已經整合好了整個Oauth2.0流程,可以減少了很多程式碼。 邏輯程式碼就不具體展示了,重中之重的配置檔案application.yml內容如下

github-base-url: https://github.com/login

spring:
	security:
		oauth2:
			client:
				registration:
					github:
						client-id: 4255eebca50558bd0579(Your client-id)
						client-secret: XXXXX(Your client-secret)
						authorizationGrantType: authorization_code
						redirect_uri_template: "{baseUrl}/login/oauth2/code/{registrationId}"
						clientName: github-client
				provider:
					github:
						token-uri: ${github-base-url}/oauth/access_token
						authorization-uri: ${github-base-url}/oauth/authorize
						user-info-uri: https://api.github.com/user
server:
port: 8888

GitHub完成授權驗證的大致流程

在這裡插入圖片描述 1.使用者點選github登入本地應用引導使用者跳轉到第三方授權頁 跳轉地址:https://github.com/login/oauth/authorize?client_id={client_id}&redirect_uri={redirect_uri}&state={state}

client_id,client_secret是註冊好Oauth APP後github提供的,需要寫在原生代碼或者配置檔案中,state也是在本地生成的。redirect_uri 就是在GitHub官網填的Authorization callback URL。

此時帶著state等引數去申請授權,但此時尚未登陸,未能通過authorize,GitHub返回code引數。

3.通過state引數和code引數,成功獲取access_token 有了access_token,只需要把access_token引數放在URL後面即可,就可以換取使用者資訊了。 訪問地址:https://api.github.com/user?access_token=xxx;

4.得到github授權使用者的個人資訊,就表明授權成功

整個流程類似於下圖,放在這裡方便大家理解。 在這裡插入圖片描述

總結

本文主要是結合自己所學知識,和眾多參考資料,探討了自己對OAuth2.0原理和第三方登入實質的一些理解,完成了第三方登入之GitHub的實踐。 希望能對大家有所幫助~ 有問題歡迎留言交流,不足之處還請多多指正。