KK 的 Web 實驗室(Day23–27)
Plus Ultra Prominence Burn
27 成為看起來很強的後端:JWT 跟 Session 怎麼組合?

上一篇 KK 老師花了很大的篇幅描述結合 Session /Cookie 和 JWT 的方式。

那既然需要驗證 Token 然後再做 JWT,為何要把兩邊的缺點結合在一起?
先來複習一下。
JWT 會遇到的問題

前面提過,原本 JWT 模式的缺點就在「儲存方式」。
使用上一個影片介紹的 In-Memory 方式 將 token 存在變數裡,使用者只要在瀏覽器按下重整,Memory 釋出後就會被登出。
所以,沒有時間做其他機制的時候,就直接存在 Local Storage 吧。
Session / Cookie 會遇到的問題

當 Client 打一個 /login 給 Server,會拿到一個 Cookie 紀錄 sid 。
而接下來的「每次」執行,不論下單、看東西…,所有行為 Server 都需要跟 Session Store 做溝通,通常會使用 Redis 這樣快取型的資料庫。(KK 老師說之後會再介紹)
一個使用者還好,但當使用者很多的時候,這個資料庫就需要越來越大。
在中心化管理下,擴充的時候也只能「垂直擴充」,也就是只能越開越大台的伺服器,無法用好幾台低階伺服器去「水平擴充」。
因此當網站流量不大,如:個人部落格,可能一個 Session Store 就夠了。
比較大的流量,如:電商網站,管理起來就會比較有挑戰性。
所以要用 JWT 或 Session/Cookie?
通常取決於「實作方式」。
如果是「純靜態網頁」,前端(使用 React、Angular)、後端分離,用 API 呼叫時,就很「適合用 JWT」 。
因為靜態頁面不用透過伺服器渲染,可以放在內容傳播網路 CDN 上(https://en.wikipedia.org/wiki/Content_delivery_network)。
此時 Static(靜態網頁)和 JWT Stateless 狀態就可以完美搭配。
(感恩前面的課程,順利聽懂 static 跟 stateless 這兩個單字 XD)
如果是「透過 Server 去渲染 Browser 」,也是就是 SSR (Server-Side Rendering)這種情形就很「適合用 Session / Cookie 模式」。https://developers.google.com/web/updates/2019/02/rendering-on-the-web
可能會寫某些框架,如:Express、Python 的 Django 或 Flask 、或用 PHP 直接渲染 HTML。
JWT 2.0 (JWT 結合 Session / Cookie)的模式是如何優化這些問題?

解決頻繁溝通的問題
這個模式在 /login 的時候拿到 token ,並在 /refresh-token 的時候才跟 In-Memory 做驗證。
而 /refresh-token 拿到的 auth token 普遍效期約 15–60 分鐘(看應用程式而定,如:網銀可能縮成 5 分鐘),因此只要在時限內都在 Memory 內,所以不用一直去做 refresh-token 。
保有 JWT 平行化(Stateless)的特性
這個模式允許我們開非常多個 Server 大量產生 auth token。
如何防止 /refresh-token 被偷走?

解決方法跟 Session / Cookie 很像。
在 Server 回傳的 Header 裡面的 Set-Cookie: 除了設定 HTTPOnly ,我們會設定一個時間條件,例如:使用 Max-Age : 30 days 。
而 /refresh-token 並不會被經常更換。
通常在做 JWT 2.0 這樣的模型時,會有個網頁介面,上面有按鈕寫著「更新 Refresh Token」。
我們在登出的時候有個 /logout 登出的 API ,會幫你把 Refresh Token 註銷掉,讓全站登出(全裝置登出)。
而雖然 auth token 在 In-memory 裡面,auth token 是短時間的,所以最慢也是等 auth token 的效期結束,就會把全部裝置登出。
目前沒有辦法達到即刻所有人登出,JWT 2.0 這個方式結合了 JWT 和 Session / Cookie 的各種好處也降低了他們的風險。
而這個模型是目前業界普遍認為比較好的方式。

28 成為看起來很強的後端:串接第三方登入-OAuth2

這個影片要來談談另外一個第三方登入模式: OAth(有非常多版本,目前用的是OAth2的規範。)
OAuth2 的機制,一樣從瀏覽器出發。

通常會看到一個 Facebook 或 Google 的超連結按鈕(一個 HTML Anchor Element) 。https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a
點下去連到網址(以 Facebook 為例)之後,習慣性會彈跳出一個新視窗,也可能會直接把當下的視窗換掉。

這時你就會看到一個 Facebook 的網址以及畫面。(如果畫面正確但網址長得很像但是錯誤,如:網址字母 o 改成數字 0,你可能要被釣魚囉)
確認正確,就可以放心地填寫帳號、密碼。

登入之後,Facebook 就會幫你導向。


因為OAuth 會要求帶一個 redirect 的網址,導回原本網站,或導去別的網站。
(網址僅作為舉例用,各種第三方服務會有自己的網址設定)
OAuth 的實作方式
以 Authorization Code 模式為例
當導向別的網站時,跟 Access Token 的差別是,Authorization Code 需要多做一個步驟。
發出的Request 帶 code=foo 跟 Facebook 拿一個 token 回來,然後再用這個 token 跟 Facebook 要資料(如:使用者 email)。



以 Access Token 模式為例(紅色線條)
當導向別的網站時,直接帶 token就能跟 Facebook 要東西(如:使用者 email)。
現在比較多傾向用 Access Token 的模式。

各種參數怎麼帶?

Redirect 的時候,根據第三方登入支援哪種模式,可以用 type 選擇要用 Authorization Code 或 Access Token 。

也可以在一開始 Browser 點擊的時候,帶參數 scope 。(也可能是其他名稱,要看第三方服務設計)
假設想要拿到使用者的 email 或 profile ,在跳出 Facebook 的登入網址時,就會告知使用者這個服務想要獲得的資訊,讓使用者決定是否要提供這些資訊。(或是允許行為,如:是否同意讓這個服務幫你發文章…)
經典面試題

面試的時候,可能被問到 OAuth 要做在前端還是後端?
現在重點來到 KK 老師指的這個地方,這個使用者登入之後的「接收方」到底是什麼。
OAuth 作在「後」端
OAuth 選擇導向時,會要求帶一個 redirect 的網址。
我們可以選擇導去別的地方做,如下圖自己(前端)網頁網址為 www.example.com ,而 redirect 導向去(後端) api.exmaple.com 。
接著再用 301 轉址回去前端頁面。

優點:安全性比較好。
一來,可以用白名單限制誰被允許做登入。
拿到 token 之後的所有操作都在後端,也不會被 Client 端看到。
缺點:需要301轉址回前端頁面。
OAuth 作在「前」端
我們可以選擇導回原本頁面去做後面的 Request。
優點:不用多開一個 endpoint 。
(什麼是 endpoint?https://stackoverflow.com/questions/9807382/what-is-a-web-service-endpoint)
缺點:token 會碰到 Client 端,就有機會被使用者帶走。
一個仍然不太安全的解決方法是,在 Client 端用 Memory 的方式去儲存。(不使用 Local Storage)
結論
實作 OAuth 機制如果有後端人力,KK 老師會建議放在後端上。
29 成為看起來很強的後端:網路概念總結

突然畫面一轉,來到一個室內空間,不太確定是哪裡,而且收音品質改變了。
KK 老師這個房間內收納空間相當驚人,光是後方兩個置頂的衣櫃,我這輩子可能都放不完。
網站五大面向
這個系列,KK 老師一開始跟我們分析網站的五大面向,交付、權限、運算、資料、儲存。

舉例來說,這些網站都有使用網頁或 API 不同的交付方式。
可能有不同的運算方式,例如遊戲類網站會用 WebSocket 來進行對接。
有些使用雲端儲存、有些使用本地端、有些使用關聯式、非關聯資料庫。
其實看到這邊開始在想,這是不是試上課程…
畢竟 IT邦幫忙鐵人賽也只有 30 天。
我們繼續看下去。
Client 到 Server 的種種
過去這個月,這一系列影片,KK 老師詳細說明從 Client 端到 Server 端整個流程,透過 DNS 進行解析,變成 IP,經過 Proxy 跟 Router ,最後到達硬體 Server 。
透過 Reverse Proxy (Nginx)的方式去進行請求轉換,如果有預算就可以用 Load Balancer 來分散在不同機器,進行擴充。
進去之後會有 Web Server (PHP、Node.js 的 Express、Python 的 Flask 或 Django…等)。
接著談實際怎麼運作(目前常見的 TCP/IP 四層架構)。從應用層、傳輸、網路、實體層。談了網路協定(規範),例如應用層的各種通訊協定(HTTP、TELNET、FTP、SMTP),也對 HTTP 著墨不少。比較沒有談到 TCP 跟 UDP ,這個部分大家可以自行 Google )https://stackoverflow.com/questions/5330277/what-are-examples-of-tcp-and-udp-in-real-life
HTTP 的格式,分成 Header 跟 Body
Header 內放了 Metadata ,包含要傳到哪裡、路徑是什麼、host 或 path 等等,也談到 URL 的格式。並且討論到裡面如何定義 domain 、接受什麼格式、權限如何帶過去…等。
Body 談的是帶過去的格式,例如 JSON 的格式、 HTML、CVS、純文字…等。
大家如果都不記得了,可以回去重看影片。
30 成為看起來很強的後端:權限總結
權限驗證的部分, KK 老師談了 API Key 模式、Basic Authentication、JWT、Cookie / Session 、OAuth 這幾種方式。
當然還有其他新的權限或自訂的方式,但也都是這些基礎的變化型,例如:把放 Header 的內容放 Body、用別的方式產生 token…等。
容易搞錯的 Authentication 跟 Authorization
權限分為 Authentication (可不可以) 跟 Authorization (什麼程度),了解什麼樣的人可以進行什麼樣的行為、得到什麼樣的資料或服務。當時 KK 老師用學生證的例子說明。
接著,權限驗證分為 Client 端和 Server 端,有 Client to Server (碰到人就是麻煩) 和 Server to Server (躲在防火牆或白名單後面)。
權限驗證又分為三種類型:Event-based (一次性驗證)、Time-based (時效性驗證)、Static (靜態驗證),這些在 API Key 跟 Basic Authentication 都會遇到。
API 走的是 Header 放 x-api-key ,是自定義的,屬於Static 模式比較多,主要看應用情境來決定。
Basic Authentication 用的 Header 是 Authorization:basic ,這個 token 是透過 Base64 (因為可能有不合法使用的字元)把使用者帳號、密碼串在一起編碼,一樣屬於 Static 模式。
JWT (JSON Web Tokens)提到,Header (用什麼方式進行 token 驗證與加密)、 Payload (放 data 的區塊,注意不要放機密資料)、 Signature (驗證中間 Payload 是否正確、有無被竄改)。
(無意間看到這個 https://jwt.io/introduction/)
保護這些資料的機制,如:雜湊(單向)、加密(雙向+鑰匙)、編碼(雙向),也有談了不少。
之後影片也談到 JWT 只要有一把 secret 就可以做到 Stateless的驗證。
Session / Cookie 說明不會用 session-based cookie 的方式去儲存資料,而是用 sid (Session ID)存起來。這些資訊會被存在 Session Store ,只要前端有 sid 通過驗證就能拿到資料。
那為了解決這個 sid 可能會被偷走,就可能透過 Server 把 sid 註銷掉。
也可以利用 Persistent Cookie (有設定時效性),而一般 Cookie 瀏覽器關掉就消失了。
JWT 和 Session / Cookie 的各種問題和結合,KK 老師也在前幾週(包含這一篇)裡面做長篇幅的討論。
最後談到 OAuth 如何做第三方登入的實作,可以往上滑直接再次複習。
最後 KK 老師,留下一個問題給大家:
「平常講的帳號、密碼註冊登入,跟這幾種模式差別在哪裡呢?」
有機會可能會再拍影片,不過 KK 爆炸忙啊…
31 成為看起來很強的後端:Web 之路怎麼走

一開始以為是鏡頭一直在前後移動,創造某種效果,結果發現只是 KK 老師自己用椅子滑前滑後…。
這個影片主要來談談,如果想走 Web 要怎麼選擇之後的方向。
「前端」開始 Web 之路
如果是正準備要踏入寫網站這個領域,最容易就是從前端靜態畫面開始。
因為不需要租主機、管理雲端,可以直接在電腦裡面做出一個頁面。
做出來之後,就算是純靜態網站,還是需要 host 在某個地方。
KK 老師介紹一個常見的網頁空間:Netlify https://www.netlify.com/
如果只會寫前端,也能輕鬆部署網站。
接下來就可以開始碰 CSS 、 SASS https://sass-lang.com/ ,增加網站豐富度。
那如果想讓網站看起來更專業,可以做微動畫,也就是滑鼠滑到按鈕可能有些小動畫,就會看起來更厲害了。
如果不想往酷炫方向走,而是想走更多資料處理的話,就能從「前端設計」慢慢往「前端工程」。
這時候重視的就是「資料流」的處理。
例如:電商網站從加入購物車到結帳過程,換頁、更改數量…等,怎麼讓資料傳輸更順暢、資料不漏、怎麼做 Cache (快取)減少跟後端傳輸的次數,像這些都是前端工程在做的。
另外一個部分著重在「共用性」,也就是各種元件怎麼更好的重複使用。
自然而然就會碰到不少前端框架,如:Angular 、 React 、 Vue…等等。
如果想做視覺效果、動畫的話,就往「前端設計」走。
如果想多做資料處理或邏輯,就往「前端工程」走。
那「後端」呢?
如果想要讓別人不知道你在幹嘛(KK 老師神比喻)可以往「後端」走。
「後端」通常處理的都是一些 API 的建置、如何拿資料、設計穩定的後端、串接第三方登入…等等。
很重要一點:後端工程是被公認沒事看起來很廢,網站出事才會出現,有點吃力不討好。
不過畢竟是苦力活,薪水可能也會好一些。
只是出事的時候,常常都是後端出問題。
前端做出一點改變,大家(老闆、投資人、其他人、不知道你在幹嘛的人)就會很有感覺。
往更「後端」走的 DBA (Database Administrator)
DBA 專門建置高可用性的 DB 、思考如何讓吞吐量增加(可以有更多 Request)、設計資料表讓後端擴充應用…等。
還有什麼跟後端有關?
跟架構比較有關的,例如要建置幾台伺服器、幾台資料庫、什麼樣的系統架構、放 AWS / GCP / 自己的主機…等等。
這些都是透過「架構師」來實作,如果是做系統的就稱為「系統架構師」(System Architect),也有人稱為「解決方案架構師」。
也有一種不只是做軟體的架構師,可能會涉及業務端、行銷端、客服…等的架構。
這樣的角色就更需要有好的溝通能力、了解商業邏輯…,通常都是由外部顧問進來,必須技術底子夠好也涉略許多。
KK 給的建議:不管打算在哪一邊深耕,理想上都能多多了解另一邊的人在做些什麼。