1. 程式人生 > 其它 >【高階Java架構師系統學習】四年Java面試遇到的問題整理

【高階Java架構師系統學習】四年Java面試遇到的問題整理

正文

先問小夥伴們一個問題,登入難嗎?“登入有什麼難得?輸入使用者名稱和密碼,後臺檢索出來,校驗一下不就行了。”凡是這樣回答的小夥伴,你明顯就是產品思維,登入看似簡單,使用者名稱和密碼,後臺校驗一下,完事了。但是,登入這個過程涵蓋的知識點是非常多的,絕不是檢索資料,校驗一下這麼簡單的事。

那麼登入都要哪些實現方式呢?i最傳統的就要是Cookie-Session這種方式了,最早的登入方式都是這樣實現的。但是隨著手機端、H5端的興起,前後端分離的模式越來越流行,基於Cookie-Session這種登入方式不是很方便,漸漸的JTW開始流行,現在大部分專案的登入方式都是基於JWT的了。那麼Cookie和JWT都是怎樣實現登入的呢?這兩種方式有什麼區別呢?我們在做登入的x時候該怎麼選擇呢?咱們先看看這兩種方式的原理。

Cookie方式

因為Http協議是無狀態的,我們後臺的服務(如Tomcat)在接收到前端傳送過來的Http請求時,是區分不出哪個請求是誰發出的,這和我們的登入功能是相違背的,登入的功能就是要區分每一個請求是由哪個使用者發出的,這就變成了有狀態,那怎麼辦呢?Cookie應運而生,Cookie是儲存在瀏覽器端的,在Cookie中儲存的內容是鍵值對,也就是name-value。瀏覽器在向後臺傳送請求的時候,會把Cookie放在請求頭中,傳送給後臺的服務,後臺的服務會從請求頭中取到Cookie,再從Cookie中取出鍵值對中jsessionid對應的值。這個jsessionid的值就是你這次會話的id,對應著服務端的一個session。

好了,到這裡session這個概念出來了,session是什麼呢?session是儲存在服務端的,每一個會話對應服務中的一個session。咱們可以把session理解為一個Map,它的key儲存的session的id,value儲存的東西就隨便了,我們在寫程式時想存啥就存啥。它的key儲存的值就是Cookie中儲存的jsessionid的值,這樣,瀏覽器傳送請求到後臺服務,後臺才能根據Cookie中的jsessionid取到對應的session,再從session中取到之前儲存的狀態,如儲存在session中的登入狀態、使用者id等。Cookie-Session機制是通用的,所有的瀏覽器都支援Cookie,就連最低端的IE都支援,你說他普遍不普遍。Session是後端容器必須支援的,如Tomcat,還有像其他的如Resin、jetty等。這些對開發人員都是透明的,無需過多關注。

Cookie-Session的由來給大家說完了,我們看看基於Cookie這種方式的登入流程,

  • 使用者在瀏覽器輸入使用者名稱、密碼,點選登入,傳送請求到後臺服務;
  • 後臺服務校驗使用者名稱、密碼,將登入狀態狀態和使用者id儲存在session中;
  • 將session的id儲存在Cookie中,通過響應頭返回到瀏覽器;
  • 當用戶點選其他功能時,向後臺傳送的請求中會自動帶上Cookie;
  • 後臺通過Cookie中的jsessionid找到對應的session,開發人員可從session中取出當前會話的登入狀態和使用者id。

基於Cookie-Session機制的登入實現方式的整體流程就是這個樣子。看上去很完美,但還是存在不少問題的,我們來看看這些問題。

分散式會話

上面的示例,我們的後臺服務只有一個,一個服務往往很難支撐服務,為了保障可靠性,最少都是部署兩個後臺服務。但是當部署多個後臺服務時,我們的session就會出現問題,看看下面的圖,

  • 假如使用者登入的請求,分配到了後臺服務1,後臺服務1的session存了使用者的登入狀態和使用者id。
  • 使用者在點選其他功能時,請求分配到了後臺服務2,可是後臺服務2的session並沒有儲存登入狀態和使用者id。

我們怎麼解決這個問題呢?其實也很簡單,第一,session集中管理,比如使用Redis;第二,所有的後臺服務在獲取session時,統一從Redis中獲取。如下所示,

我們可以使用中介軟體Spring-Session和Redis就可以解決這個問題。

CORS

使用Cookie實現登入的另外一個問題就是跨域,現在往往都採用前後端分離的方式進行開發,在開發的過程中,前端和後端通常不在一個域下,由於瀏覽器的同源策略,Cookie不能傳入到後端。至於同源策略,不明白的小夥伴可以問一下度娘,這裡不過多介紹了。要解決這個問題,在前端、後端都要進行設定,在我的另一篇文章《前後端分離|關於登入狀態那些事》中有詳細的介紹。總體歸納為:

  • 後端設定CORS允許跨域的域名,並且withCredentials設定為true;
  • 前端在向後端傳送請求時,也需要設定withCredentials = true;

這樣,我們的Cookie就可以實現跨域了。不進行這些設定,Cookie跨域是不可能的,同源策略保證了我們Cookie的安全。

CSRF

CSRF,這個CORS是不一樣的,長的比較像,也比較容易混。CSRF往往和系統的安全扯上聯絡,也是等保測試中比較重要的測試內容,它也是和Cookie有關的,大體的流程是這樣的,

  • 使用者登入了A網站,並沒有退出;
  • 此時,使用者又訪問了B網站;
  • 在B網站有個隱藏的請求,請求了A網站的一個重要的介面,比如:轉賬、支付等。
  • 在請求A網站的同時,帶上了A網站的Cookie,所以一些危險的操作就成功了。

關於CSRF的攻防,在我前面的文章《CSRF的原理與防禦 | 你想不想來一次CSRF攻擊?》中有詳細的介紹。總之,使用Cookie實現登入是需要重點防範一下CSRF攻擊的。

JWT方式

近年來,由於手機端的興起,前後端分離開發方式的流行,JWT這種登入的實現方式悄然興起,那麼什麼是JWT呢?JWT是英文JSON Web Token的縮寫,它由3部分組成,

  • header,一般情況下儲存兩個資訊,1型別,一般都是JWT;2加密演算法,比如:HMAC、RSA等;
  • payload,這裡就儲存登入的相關資訊了,比如:登入狀態、使用者id、過期時間等。
  • signature,簽名,這個是將header、payload和金鑰的資訊做一次加密,後臺在接收到JWT的時候,一定要驗籤,謹防JWT的偽造。

下面咱們看看JWT的登入實現,

我們看到整體的流程和Cookie的實現方式是一樣的,只不過是沒有用到Cookie、Session。那麼它與Cookie-Session的區別是什麼呢?

  • 登入狀態、使用者id並沒有儲存到session,而是存在JWT的payload裡,返回給了前端。
  • 在前端JWT不會自動儲存到Cookie中,前端開發人員要處理JWT的儲存問題,比如LocalStorage
  • 再次發起請求,JWT不會自動放到請求頭中,需前端同學手動設定
  • 後端從請求頭中取出JWT,驗籤通過後,拿到登入狀態、使用者id,不是從session中取

相比Cookie的方式,JWT的方式需要更多的開發工作量。那麼其他的問題存在嗎?我們一個一個看。

分散式會話

我們後臺部署多個服務,會有分散式會話的問題嗎?

無論請求被分配到哪一個後臺服務中,登入狀態和使用者id都是從JWT中取出來的,不會出現分散式會話的問題。我們在後臺部署叢集的時候,根本不用care這個問題。

CORS

Cookie的跨域受到同源策略的保護,不經過特殊的設定,是不能夠跨域的。那麼JWT呢?JWT是前端同學手動在請求頭中設定的,如果向其他的域傳送請求要注意,稍不注意,在請求的時候,呼叫了封裝的公共方法,就會把JWT傳送給其他域的後臺,前端的小夥伴要打起精神啊。

CSRF

Cookie的方式,B訪問A網站,會把A的Cookie帶上,從而造成了安全隱患。那麼JWT呢?JWT在前端儲存在A網站的域下,B在訪問A網站時,是拿不到A網站的JWT的,那麼也不可能在請求頭中設定JWT,A網站的後臺拿不到JWT,也不會做其他操作。所以,JWT可以很好的防止CSRF攻擊。

文末java面試題,進階技術大綱,架構資料分享

我將這三次阿里面試的題目全部分專題整理出來,並附帶上詳細的答案解析,生成了一份PDF文件,有興趣的朋友們可以點選這裡即可免費領取

  • 第一個要分享給大家的就是演算法和資料結構
  • 第二個就是資料庫的高頻知識點與效能優化
  • 第三個則是併發程式設計(72個知識點學習)
  • 最後一個是各大JAVA架構專題的面試點+解析+我的一些學習的書籍資料

還有更多的Redis、MySQL、JVM、Kafka、微服務、Spring全家桶等學習筆記這裡就不一一列舉出來