<mark id="n9zld"></mark>

      <thead id="n9zld"><video id="n9zld"></video></thead>

      <ins id="n9zld"></ins>

        <b id="n9zld"></b>

            <font id="n9zld"><video id="n9zld"></video></font>
            <b id="n9zld"></b>

              <dfn id="n9zld"><video id="n9zld"></video></dfn>

                OAuth 2.0 的四種方式

                作者: 阮一峰

                日期: 2019年4月 9日

                騰訊課堂 NEXT 學院

                上一篇文章介紹了 OAuth 2.0 是一種授權機制,主要用來頒發令牌(token)。本文接著介紹頒發令牌的實務操作。

                下面我假定,你已經理解了 OAuth 2.0 的含義和設計思想,否則請先閱讀這個系列的上一篇文章

                進入正文之前,插播一則活動消息。

                4月22日(周一)到4月29日(下周一),每天晚上八點都有兩小時的免費直播課,體系化介紹高級前端開發知識,網易云課堂主辦。詳細介紹請看本文結尾,歡迎關注。

                RFC 6749

                OAuth 2.0 的標準是 RFC 6749 文件。該文件先解釋了 OAuth 是什么。

                OAuth 引入了一個授權層,用來分離兩種不同的角色:客戶端和資源所有者。......資源所有者同意以后,資源服務器可以向客戶端頒發令牌。客戶端通過令牌,去請求數據。

                這段話的意思就是,OAuth 的核心就是向第三方應用頒發令牌。然后,RFC 6749 接著寫道:

                (由于互聯網有多種場景,)本標準定義了獲得令牌的四種授權方式(authorization grant )。

                也就是說,OAuth 2.0 規定了四種獲得令牌的流程。你可以選擇最適合自己的那一種,向第三方應用頒發令牌。下面就是這四種授權方式。

                • 授權碼(authorization-code)
                • 隱藏式(implicit)
                • 密碼式(password):
                • 客戶端憑證(client credentials)

                注意,不管哪一種授權方式,第三方應用申請令牌之前,都必須先到系統備案,說明自己的身份,然后會拿到兩個身份識別碼:客戶端 ID(client ID)和客戶端密鑰(client secret)。這是為了防止令牌被濫用,沒有備案過的第三方應用,是不會拿到令牌的。

                第一種授權方式:授權碼

                授權碼(authorization code)方式,指的是第三方應用先申請一個授權碼,然后再用該碼獲取令牌。

                這種方式是最常用的流程,安全性也最高,它適用于那些有后端的 Web 應用。授權碼通過前端傳送,令牌則是儲存在后端,而且所有與資源服務器的通信都在后端完成。這樣的前后端分離,可以避免令牌泄漏。

                第一步,A 網站提供一個鏈接,用戶點擊后就會跳轉到 B 網站,授權用戶數據給 A 網站使用。下面就是 A 網站跳轉 B 網站的一個示意鏈接。

                
                https://b.com/oauth/authorize?
                  response_type=code&
                  client_id=CLIENT_ID&
                  redirect_uri=CALLBACK_URL&
                  scope=read
                

                上面 URL 中,response_type參數表示要求返回授權碼(code),client_id參數讓 B 知道是誰在請求,redirect_uri參數是 B 接受或拒絕請求后的跳轉網址,scope參數表示要求的授權范圍(這里是只讀)。

                第二步,用戶跳轉后,B 網站會要求用戶登錄,然后詢問是否同意給予 A 網站授權。用戶表示同意,這時 B 網站就會跳回redirect_uri參數指定的網址。跳轉時,會傳回一個授權碼,就像下面這樣。

                
                https://a.com/callback?code=AUTHORIZATION_CODE
                

                上面 URL 中,code參數就是授權碼。

                第三步,A 網站拿到授權碼以后,就可以在后端,向 B 網站請求令牌。

                
                https://b.com/oauth/token?
                 client_id=CLIENT_ID&
                 client_secret=CLIENT_SECRET&
                 grant_type=authorization_code&
                 code=AUTHORIZATION_CODE&
                 redirect_uri=CALLBACK_URL
                

                上面 URL 中,client_id參數和client_secret參數用來讓 B 確認 A 的身份(client_secret參數是保密的,因此只能在后端發請求),grant_type參數的值是AUTHORIZATION_CODE,表示采用的授權方式是授權碼,code參數是上一步拿到的授權碼,redirect_uri參數是令牌頒發后的回調網址。

                第四步,B 網站收到請求以后,就會頒發令牌。具體做法是向redirect_uri指定的網址,發送一段 JSON 數據。

                
                {    
                  "access_token":"ACCESS_TOKEN",
                  "token_type":"bearer",
                  "expires_in":2592000,
                  "refresh_token":"REFRESH_TOKEN",
                  "scope":"read",
                  "uid":100101,
                  "info":{...}
                }
                

                上面 JSON 數據中,access_token字段就是令牌,A 網站在后端拿到了。

                第二種方式:隱藏式

                有些 Web 應用是純前端應用,沒有后端。這時就不能用上面的方式了,必須將令牌儲存在前端。RFC 6749 就規定了第二種方式,允許直接向前端頒發令牌。這種方式沒有授權碼這個中間步驟,所以稱為(授權碼)"隱藏式"(implicit)。

                第一步,A 網站提供一個鏈接,要求用戶跳轉到 B 網站,授權用戶數據給 A 網站使用。

                
                https://b.com/oauth/authorize?
                  response_type=token&
                  client_id=CLIENT_ID&
                  redirect_uri=CALLBACK_URL&
                  scope=read
                

                上面 URL 中,response_type參數為token,表示要求直接返回令牌。

                第二步,用戶跳轉到 B 網站,登錄后同意給予 A 網站授權。這時,B 網站就會跳回redirect_uri參數指定的跳轉網址,并且把令牌作為 URL 參數,傳給 A 網站。

                
                https://a.com/callback#token=ACCESS_TOKEN
                

                上面 URL 中,token參數就是令牌,A 網站因此直接在前端拿到令牌。

                注意,令牌的位置是 URL 錨點(fragment),而不是查詢字符串(querystring),這是因為 OAuth 2.0 允許跳轉網址是 HTTP 協議,因此存在"中間人攻擊"的風險,而瀏覽器跳轉時,錨點不會發到服務器,就減少了泄漏令牌的風險。

                這種方式把令牌直接傳給前端,是很不安全的。因此,只能用于一些安全要求不高的場景,并且令牌的有效期必須非常短,通常就是會話期間(session)有效,瀏覽器關掉,令牌就失效了。

                第三種方式:密碼式

                如果你高度信任某個應用,RFC 6749 也允許用戶把用戶名和密碼,直接告訴該應用。該應用就使用你的密碼,申請令牌,這種方式稱為"密碼式"(password)。

                第一步,A 網站要求用戶提供 B 網站的用戶名和密碼。拿到以后,A 就直接向 B 請求令牌。

                
                https://oauth.b.com/token?
                  grant_type=password&
                  username=USERNAME&
                  password=PASSWORD&
                  client_id=CLIENT_ID
                

                上面 URL 中,grant_type參數是授權方式,這里的password表示"密碼式",usernamepassword是 B 的用戶名和密碼。

                第二步,B 網站驗證身份通過后,直接給出令牌。注意,這時不需要跳轉,而是把令牌放在 JSON 數據里面,作為 HTTP 回應,A 因此拿到令牌。

                這種方式需要用戶給出自己的用戶名/密碼,顯然風險很大,因此只適用于其他授權方式都無法采用的情況,而且必須是用戶高度信任的應用。

                第四種方式:憑證式

                最后一種方式是憑證式(client credentials),適用于沒有前端的命令行應用,即在命令行下請求令牌。

                第一步,A 應用在命令行向 B 發出請求。

                
                https://oauth.b.com/token?
                  grant_type=client_credentials&
                  client_id=CLIENT_ID&
                  client_secret=CLIENT_SECRET
                

                上面 URL 中,grant_type參數等于client_credentials表示采用憑證式,client_idclient_secret用來讓 B 確認 A 的身份。

                第二步,B 網站驗證通過以后,直接返回令牌。

                這種方式給出的令牌,是針對第三方應用的,而不是針對用戶的,即有可能多個用戶共享同一個令牌。

                令牌的使用

                A 網站拿到令牌以后,就可以向 B 網站的 API 請求數據了。

                此時,每個發到 API 的請求,都必須帶有令牌。具體做法是在請求的頭信息,加上一個Authorization字段,令牌就放在這個字段里面。

                
                curl -H "Authorization: Bearer ACCESS_TOKEN" \
                "https://api.b.com"
                

                上面命令中,ACCESS_TOKEN就是拿到的令牌。

                更新令牌

                令牌的有效期到了,如果讓用戶重新走一遍上面的流程,再申請一個新的令牌,很可能體驗不好,而且也沒有必要。OAuth 2.0 允許用戶自動更新令牌。

                具體方法是,B 網站頒發令牌的時候,一次性頒發兩個令牌,一個用于獲取數據,另一個用于獲取新的令牌(refresh token 字段)。令牌到期前,用戶使用 refresh token 發一個請求,去更新令牌。

                
                https://b.com/oauth/token?
                  grant_type=refresh_token&
                  client_id=CLIENT_ID&
                  client_secret=CLIENT_SECRET&
                  refresh_token=REFRESH_TOKEN
                

                上面 URL 中,grant_type參數為refresh_token表示要求更新令牌,client_id參數和client_secret參數用于確認身份,refresh_token參數就是用于更新令牌的令牌。

                B 網站驗證通過以后,就會頒發新的令牌。

                寫到這里,頒發令牌的四種方式就介紹完了。下一篇文章會編寫一個真實的 Demo,演示如何通過 OAuth 2.0 向 GitHub 的 API 申請令牌,然后再用令牌獲取數據。

                (正文完)

                前端高級開發工程師免費直播課

                經過多年的發展,前端工程師的地位日益提升,越來越多的人想往前端的方向發展。

                但是,市場對前端工程師的要求也越來越高,深入掌握底層技術的高級前端,才能在市場上找到自己立足之地。

                為了幫助大家深入了解高級前端的學習要點,4月22日(周一)到4月29日(下周一),網易云課堂推出了前端進階免費直播課

                • 周一(4月22日):《前端不會點 node 怎么行,node http 模塊詳解》
                • 周二(4月23日):《進階面試必備的三大技術題》
                • 周三(4月24日):《前端高級工程師核心裝備之柯里化》
                • 周四(4月25日):《手把手帶你實現 Vue 的 MVVM》
                • 周五(4月26日):《JQuery 原理分析》
                • 周六(4月27日):《用迭代器模式讓你的脫離繁重的數據處理 》
                • 周日(4月28日):《前端性能--JS的防抖節流實現與案例場景》
                • 周一(4月29日):《阿里巴巴 P5 面試題講解》

                (更多介紹點擊這里

                他們邀請了網易資深前端工程師,免費直播分享實戰中的經驗方法。內容涉及網易內部自定組件庫工具分享,前端開發相關知識,深度剖析 JavaScript 等。

                這個直播面向前端初、中級開發工程師,每天2個小時,都是一些干貨分享并且不收費,建議想進階的同學堅持學習。大家可以微信掃碼,添加助教,獲取聽課地址。

                (完)

                留言(29條)

                Implicit Flow 返回 access token 時,不應該用 query (?token=TOKEN-xxx) 而是 fragment (#TOKEN-xxx)

                這在 RFC 6749 里是有規定的 https://tools.ietf.org/html/rfc6749#section-4.2

                在 implicit 中使用 fragment 傳遞 token 是很巧妙的設計,具體原因可見:https://www.chrisyue.com/?p=3178

                @chrisyue:

                謝謝指出,這一點真沒注意到,漲知識了。我一會就把原文改掉。

                Demo 會使用 vue 和axios嗎? 還是原始的ajax,最近正好碰到這個問題了,token過期后,底層需要能自動去刷新token,還得避免 有多個并發請求的時候,會不會導致這些請求同時都在進行刷新token ?

                阮老師寫的通俗易懂

                單點登錄一般采用哪種比較多?

                授權碼方式,前端去后端拿了一個授權碼,然后拿著授權碼再去后端拿令牌,授權碼和令牌都是后端產生的,為什么這種方式比直接拿令牌安全呢?

                引用coderlim的發言:

                授權碼方式,前端去后端拿了一個授權碼,然后拿著授權碼再去后端拿令牌,授權碼和令牌都是后端產生的,為什么這種方式比直接拿令牌安全呢?

                因為獲取授權碼的方式是通過瀏覽器跳頁(get請求),返回的授權碼展示在地址欄,安全性不高。而獲取令牌可以使用post請求。另外,因為授權碼與發起請求的URL是關聯的,所以另一個網站使用你的授權碼是無法成功得到令牌的。

                請問一下:A網站拿到B網站頒發的令牌后,是否直接將token返回給訪問A網站的瀏覽器?如果是,當用戶再次通過瀏覽器、攜帶token訪問A網站的時候,A如何校驗該令牌是否有效呢?A網站的后端會保存B網站之前返回的token,然后直接比較是否相等,還是A網站攜帶瀏覽器發出的token,去B網站校驗?

                引用DanielDuan的發言:

                請問一下:A網站拿到B網站頒發的令牌后,是否直接將token返回給訪問A網站的瀏覽器?如果是,當用戶再次通過瀏覽器、攜帶token訪問A網站的時候,A如何校驗該令牌是否有效呢?A網站的后端會保存B網站之前返回的token,然后直接比較是否相等,還是A網站攜帶瀏覽器發出的token,去B網站校驗?

                首先作者說的獲取令牌有多種方式,如果是通過授權碼,令牌是發到A后臺的,如果是隱藏式,那么是發到前端的,也就是給瀏覽器的。這個token是B產生的,當然是在訪問B資源的時候在B驗證

                引用LouXudong的發言:

                因為獲取授權碼的方式是通過瀏覽器跳頁(get請求),返回的授權碼展示在地址欄,安全性不高。而獲取令牌可以使用post請求。另外,因為授權碼與發起請求的URL是關聯的,所以另一個網站使用你的授權碼是無法成功得到令牌的。

                授權碼是B應用用來驗證A應用的請求是經過用戶登陸驗證的

                第一種授權方式里面,獲取access_token時帶上的redirect_uri參數,RFC 6749里面的解釋是拿來做驗證的,具體可見: https://tools.ietf.org/html/rfc6749#section-4.1

                是不是意味著A網站持有用戶授權過的B網站access token和refresh token的話,自身不需要用戶再次授權就可以一直訪問B網站上的資源.

                老師你好 如果要做一個api平臺 ,做成兩個系統 , 一個是后臺系統 給用戶授權可用的接口 一個是客戶訪問的系統 后臺系統管理員授權之后 客戶可以調用已授權的接口 , 這種應用場景 適用于哪種授權模式呢? 請老師指教一下

                用戶對什么資源進行授權,這里并沒有體現出來。客戶端想要獲取用戶的資源可能是各種各樣的,而認證的流程是一樣的。

                是不是應該有參數讓客戶端指定獲取用戶哪方面的資源呢?

                嗯呢,不錯,很容易的就了解了登錄授權機制
                但是我有一個問題,我從YouTobe的視頻APP中分享視頻到Twitter APP中,卻可以直接喚起Twitter APP,并沒有經過登錄與授權的步驟,這會是神馬原因呢?

                建議微信文檔直接鏈接此文章, 清晰多了

                關于授權碼模式的疑問:
                文中寫到“第四步,B 網站收到請求以后,就會頒發令牌。具體做法是向redirect_uri指定的網址,發送一段 JSON 數據”

                問題是:既然是后端獲取,我理解應該直接是A在后端拿到code后直接帶著授權碼發請求給B,B直接響應給A token就可以了
                但是為什么是B又多了一道子,b在請求redirct_uri,向這個地址發送請求給A,A在接收token。

                引用coderlim的發言:

                授權碼方式,前端去后端拿了一個授權碼,然后拿著授權碼再去后端拿令牌,授權碼和令牌都是后端產生的,為什么這種方式比直接拿令牌安全呢?

                不一樣,這里面有三者參與:A_C【瀏覽器】、B_S【授權中心】、A_S【網站A的后端】
                A_C 先去與 B_S 交互,拿到 code
                然后code 給A_S
                A_S 與 B_S 交互,拿到 Token。 Token 不會暴露給 A_C
                【我的疑惑在于,難道之后A_C 請求用戶 在B_S 的個人數據,都需要 經過A_S的中轉嗎?】

                1、授權碼的方式:
                為了保證令牌的不泄露,是否所有的A瀏覽器 向B請求數據,都需要 經過 A的后端去轉發呢?
                2、隱藏式:
                看文中的例子,似乎沒有向B提供密碼呢?難道純前端的應用,無須向B備案,無須密碼就可以直接獲取令牌嗎?
                3、憑證式:
                關于憑證式沒有理解到何為 針對第三方應用?而且 密碼也是直接暴露在A端的了嗎?

                突然想通了 1、令牌就是要暴露出去的,而不用暴露出去的是 A的后端的 secret

                @wenxin667:

                文章里應該寫錯了,redirect_uri參數 只是用來驗證是否有效,authorization server 會直接響應 access_token 數據

                其實我想知道點擊同意授權,B的客戶端做了什么?看了很多篇,都有點蒙蒙的,覺得沒講明白是因為:沒說明白哪部分是第三方應用客戶端做的,還是第三方應用服務端做的。

                第一步的clientid 是B的客戶端id還是A的客戶端id啊?

                大佬能講一講access_token前面的Bearer是啥意思嗎?

                引用天亮前說晚安的發言:

                第一步的clientid 是B的客戶端id還是A的客戶端id啊?

                是 A 網站的。因為之前 A 網站要在授權服務器那注冊,會被分配一個 id。后面去交互時候要帶上 id 來標識自己身份。

                引用pangtu的發言:

                關于授權碼模式的疑問:
                文中寫到“第四步,B 網站收到請求以后,就會頒發令牌。具體做法是向redirect_uri指定的網址,發送一段 JSON 數據”

                問題是:既然是后端獲取,我理解應該直接是A在后端拿到code后直接帶著授權碼發請求給B,B直接響應給A token就可以了
                但是為什么是B又多了一道子,b在請求redirct_uri,向這個地址發送請求給A,A在接收token。

                為了進一步保證安全,即使你拿到了 A 的 AUTHORIZATION_CODE、client_i,甚至client_secret,但你沒有控制 A 的網站,你依然拿不到 access_token。access_token只發向已經在 B 注冊的域名。

                授權碼模式,token只存在后端的話,那同一用戶每次訪問資源,后端如何辨別出該用戶對應的token呢?

                老師,看了你的文章對oauth2有了基本的了解。多謝!

                另外,我想請教使用vue前端+springboot后臺如何實現授權碼登錄認證,不知道該怎么跳轉?

                第二種認證方式最后有這樣一段話:

                這種方式把令牌直接傳給前端,是很不安全的。因此,只能用于一些安全要求不高的場景,并且令牌的有效期必須非常短,通常就是會話期間(session)有效,瀏覽器關掉,令牌就失效了。

                這個session是B的session還是A的呢。如果是用戶在A中的sessison,那么session是否終結B應用應該是不知道的。反之亦然。所以,對session失效令牌就失效了這句話感到不理解,希望老師能夠講解下

                我要發表看法

                «-必填

                «-必填,不公開

                «-我信任你,不會填寫廣告鏈接

                99爱视频