# Token
現在正在開發一個信用卡管家的APP,可以從郵箱里面讀郵件,匯總形成報表 。
但是這個程序需要讀網易郵箱,需要用戶名和密碼,用戶并不信任這個小網站
但是如果不用用戶名和密碼,又怎么登錄呢?
可以提供一個**新的入口**,使用網易賬號登錄,點進去了以后,實際上會**重定向**到網易的認證系統中去。
網易的認證系統會讓用戶輸入用戶名和密碼,并且詢問是否允許信用卡管家訪問網易郵箱。
如果用戶確認了,就會重定向到信用卡管家的網站上,同時會帶來一個token。
信用卡管家網站就可以使用token來訪問網易郵箱了。
這樣,整個過程中,信用卡管家網站不會接觸到用戶名和密碼。
那么網易怎么知道是信用卡管家這個網站在申請授權呢?
首先信用卡管家需要在網易上注冊一下,然后網易會頒發一個app_id和app_secret。
當用戶點擊第三方登陸的時候,會把app_id和app_secret傳過去,這樣網易就知道是‘信用卡管家’這個應用在申請授權了。
下圖為流程:

- 瀏覽器點擊進去的時候,信用卡管家會返回給瀏覽器一個URL,里面包含了app_id,鏈接為 `www.163.com/xxxx?appid=xxx&return_uri=https://www.a.com/callback`
首先訪問的是`www.163.com`,然后攜帶了`appid`,然后告訴網易認證中心,認證成功以后的還需要跳轉到我自己的網站上,也就是return_uri,它的意思是,如果認證成功了以后,會回轉到信用卡管家`https://www.a.com/callback`這個頁面來
- 瀏覽器重定向到網易認證中心,同時攜帶了app_id。也就是告訴網易,是信用卡管家這個應用在尋求授權。
由網易認證中心的返回它的登錄界面。
- 用戶使用網易賬號登錄,同時點擊同意授權給信用卡管家。
網易認證中心會返回一個token,這個token是嵌在`https://www.a.com/callback#token=<生成的token>`里面的。
- 然后瀏覽器訪問`https://www.a.com/callback#token=<生成的token>`,目的是把token傳給信用卡管家,以便于它繼續用這個token 來訪問網易郵箱了
- 瀏覽器自己也會把token取出來。
可以看出整個流程里面用戶名和密碼都沒有經過信用卡管家,它能拿到的就只是token而已。
為什么我們要用JavaScript去讀取token啊?
這樣后端服務器就不用參與了,少了很多交互的過程。工作都可以終止于前端。
我們可以再看一下這個鏈接`https://www.a.com/callback#token=<生成的token>`,里面的#號就叫hash fragment,它只會停留在瀏覽器端,只有Javascript才能訪問它,而且不會通過HTTP請求發到其他服務器上,可以提高安全性。
但是問題又來了,這個token是以明文的形式發到瀏覽器的,雖然是HTTPS的,但是如果瀏覽器的歷史記錄或者訪問日志被盜了怎么辦,一樣能拿到。
# Authorization Code + Token
上面我們說了,token是明文傳遞的,雖然傳播的路徑是加密的(HTTPS),但是在瀏覽器本地存儲中依然可以找到。
那么我們可以引入應該 Authorization Code的中間層。
當用網易賬號登錄的時候,網易認證中心返回的是一個授權碼(authorization code)而不是token。
那么信用卡管家服務器端取到這個code以后,還需要在后臺再次訪問網易認證中心,然后才可以得到真正的token

- 前5個步驟都一樣,無非是瀏覽器先從信用卡管家的服務器端拿到app_id,然后傳遞給網易,由網易彈出登錄界面,進行登錄
區別是,網易返回的是code而不是token,`https://www.a.com/callback?code=3679`
- 瀏覽器依舊會把code傳給信用卡管家的服務器,由它向網易申請token,`https://www.163.com/xxx?appid=xxx&secret=xxxx&code=3679&return_uri=https://www.a.com/callback`,需要把appid和returl_uri傳遞過去的原因是之前都出瀏覽器傳的,而現在信用卡管家自己把自己當做另一個瀏覽器而已。
- 網易回復一個token,`https://www.a.com/callback?token=6789`
還是與之前同樣的問題,code依然是明文的,可以在瀏覽器記錄里面找到。
可以這樣,比如讓授權碼與app_id,app_secret相關聯,也就是通過他們運算出來,這樣,只有信用卡管家服務器發出的token請求才合法。
也可以讓授權碼有時間限制,比如說過一段時間失效,這樣,一個授權碼只能換一次token。
本文所述的其實就是OAuth的三種認證方式: