前後端分離,分布式微服務下的挑戰——單點登錄

2020-12-26 簡單說架構

前後端分離,分布式微服務下的挑戰——單點登錄

前後端分離

前後端分離,不僅僅是一種開發模式,也是一種服務的發布模式。前後端均可以獨立發布到任意可支撐的容器中。比如後端可以發布到Tomcat中,或者使用框架(如Spring Boot或Dubbo)自帶的內置容器,前端如果是靜態可直接基於nginx發布,如果是SSR,可基於Node環境運行,通過PM2工具進行管理。而如果是App,則直接發布到應用市場,由用戶自行去下載。

分布式

分布式,顧名思義,分布式的部署方式。傳統的web項目不考慮高並發,高可用等,通常都是部署在一臺獨立的伺服器上。而分布式要求項目必須考慮高並發,高可用的情況,同一個服務會分別發布到若干臺伺服器上。這些伺服器,通過負載均衡共同承擔並發壓力,相互備份冗餘以達到高可用的目的。

微服務

最早的分布式,總是將某個應用完整的分別部署,但是,這樣的一個結果就是:假設應用中,只有部分服務或接口,承受了較大的壓力,而另一部分幾乎無壓力。那麼,這種完整的分布式部署方式,無疑是對伺服器的一種浪費,且沒有完全發揮出伺服器的能力。所以,微服務要求對應用做更細化的拆分,再通過RPC框架(如Dubbo 或 Spring Cloud)等把它們連接起來構成一個整體。這樣,就可以對服務做出更靈活的部署方式,以更加充分的利用伺服器的資源。

挑戰

前後端分離,分布式微服務下,雖然可以應對更高的並發,但是,也給開發人員(基於不只是開發人員)帶來了更多的挑戰。我們就從一些簡單的場景入手,不斷的去深入挖掘,在這種新的服務模式下,都會有哪些挑戰,而我們又該如何去解決?

單點登錄

事實上,在傳統web項目中,單點登錄也可能是一個需要去解決的問題。假設某公司有兩個系統,如CMS內容管理系統,積分商城系統。某天,老闆說:為什麼我在內容管理系統已經登錄了,到了積分商城系統怎麼還要我重新登錄呢?這時候,就該考慮去做一個單點登錄了。不過,新服務模式下的單點登錄,似乎與原來又有所不同。因為要服務的運行模式更多樣化了。原來的服務可能都是放在Tomcat中的,而現在,可能有項目直接基於nginx發布,也有項目基於Node發布。事實上,更多的場景是在nginx或Node中的,這是因為,前後端分離的情況下,前端項目通常是獨立發布的,而後端項目,通常是一個或若干個項目,且它們的能力從外部看來,通常只是一系列接口的集合。那麼,我們就來聊聊,在這種前端項目以前端方式部署的情況下,如何實現單點登錄?需要明確的是,這裡,我們只討論各個前端項目之間如何去統一它們的登錄狀態。至於具體的登錄鑑權,以及和後臺接口交互時的鑑權,我們將在後續的Token機制中聊到。

單點登錄的基本原理

獨立服務中,我們的登錄通常是基於Session來做的,這是因為,在同一個服務中,雖然用戶每次請求使用的http或https協議是無狀態的,但是用戶的Session的id是相同的。因此,我們在伺服器中,在Session中存儲一個用戶狀態,用戶之後的每次請求就都可以讀取到這個狀態。而在多項目組合的情況下,這種狀態無法保持了,因為Session的id不同了,也就是說Session不同了。(先不考慮同一服務分布式部署的情況)那麼,在這種情況下,該如何保持多項目用戶狀態的統一呢?事實上,單點登錄的原理並不複雜,它做的,就是把認證中心做了抽離。即把所有項目的登錄都統一到了一個項目中。我們假設該項目名為user-center,另有一個項目cms,那麼,cms如何和user-center統一登錄狀態呢?很簡單,如下:

沒錯,就是做了一次跳轉,因為跳轉了一次user-center,那麼,就相當於又到了同一個服務中,此時,就得到了一個統一的用戶狀態。於是登錄狀態又得到了統一。那麼,該如何做登錄呢?事實上,上圖中為了便於理解,省略了一些內容,完整單點登錄邏輯如下:

圖看起來還挺複雜的,但是本質並不難,核心過程如下:

用戶訪問受限資源時,會由原項目跳轉到認證中心。認證中心檢查用戶登錄狀態,未登錄則跳轉到登錄頁要求登錄,用戶登錄時,依然使用認證中心統一驗證。用戶登錄驗證通過或本身已經登錄,則返回令牌給用戶。用戶通過令牌再次訪問受限資源時,通過認證中心校驗令牌有效性。有效則訪問,無效則重新登錄。分析上述流程,再結合前後端分離,可以整理出一個在前後端分離場景下更合理的單點登錄驗證模型,如下:

如圖中所示,只需要在cms無token或token無效的情況下,跳轉一次user-center取得token,此時,cms就可以通過token自行和後臺API接口服務完成相關的鑑權了。各個系統都通過user-center取得token,只要保證token是一致的,那麼,各系統通過後臺API取得的用戶狀態就是一致的。

代碼實現

以下提供一個單點登錄的代碼實現,涉及cms,admin,user-center三個系統。注意,在生成token時,後臺簡單使用了通過user-center發來的請求中得到的sessionId,這事實上是存在一系列安全問題的,這些問題,我們將在token機制中解決。介紹一下相關項目基本技術框架:後臺項目:Spring Boot。cms:nuxt框架,SSR模式(服務端渲染)。admin,user-center:nuxt框架,SPA模式(客戶端渲染)。在admin和cms添加中間件,用於校驗token有效性,如無token或token失效,則跳轉到user-center。在user-center中,添加一個token分發頁面,用於分發token並跳回。demo是一個最簡實現,僅供基本邏輯的演示。user-center是一個SPA項目,所以前端直接提供一個可訪問的頁面 /user/token用於token的分發,代碼如下:

<template><div> 頁面跳轉中……</div></template><script>exportdefault {name: "token", mounted() {let source = $nuxt.$route.query.sourcelet token = sessionStorage.getItem('TOKEN')if (!token) { token = 'abcd' sessionStorage.setItem('TOKEN', token) }if (source.indexOf('?') >= 0) { source += '&token=' + token } else { source += '?token=' + token }window.location.href = source } }</script><stylescoped></style>

該頁面的核心邏輯是:從sessionStorage中獲取或新生成token,把Token附帶到原地址後面,並跳轉回去。admin中包含一個中間件,路由變化時執行,代碼如下:

import Config from'@/config.json'exportdefaultasyncfunction({ app, redirect, req, route }) {let token = sessionStorage.getItem('TOKEN')if (!token) { token = route.query.tokenif (!token) {let currentUrl = window.location currentUrl = encodeURIComponent(currentUrl)return redirect(Config.tokenUrl + '?source=' + currentUrl) } sessionStorage.setItem('TOKEN', token) }}

核心邏輯是:從sessionStorage中獲取token,則嘗試從query參數中獲取,如還沒有,則將當前頁面地址包裝成source參數,跳轉到 user-center中的 /user/token去獲取token。cms中也包含一個中間件,功能上和admin中的差不多,但是,由於cms採用的是SSR模式,所以,寫法上有所不同,如下:

import Config from'@/config.json'exportdefaultasyncfunction({ app, redirect, req, route }) {let token = app.$cookies.get("TOKEN")if (!token) { token = route.query.tokenif (!token) {let currentUrl = '://' + req.headers.host + req.originalUrl currentUrl = encodeURIComponent(currentUrl)return redirect(Config.tokenUrl + '?source=' + currentUrl) } app.$cookies.set('TOKEN', token) }}

如下,邏輯上和admin是一致的,不同的是,由於在SSR模式下,sessionStorage、window等對象無法使用,所以我們需要通過cookies去存儲token,並通過req對象來獲取當前頁面的地址。

試運行

運行結果,你會發現,無論你打開admin還是cms,如果在當前項目中無法獲取到token,都會跳轉到user-center,取得token後再跳轉回原地址。也就是說,我們在三個項目中,拿到了統一的token。再加上後臺API的配合,就解決了單點登錄的問題。但是,demo中的寫法是簡單的,要實現真正能夠在生成上運行的單點登錄,還需要解決以下一些問題:

token如何生成?token如何保證安全性?這兩個問題,我們將在token機制中解決。

相關焦點

  • 網際網路系統架構為什麼要做前後端分離呢?
    在現在的網際網路架構中,前後端分離已經是一個非常常見的系統架構方式了,但是我們將前後端分離以後,感覺項目的架構比傳統的分層架構更複雜了,需要的人力資源也更多了,甚至項目周期也變得更長了,既然看上去好處不大,為什麼還要做前後端分離呢?
  • 「技術貼」微服務中臺技術解析之分布式事務方案和實踐
    通常資料庫設計文檔會對「輕易」做具體的定義,比如在磁碟壞道,機器停電重啟等條件下不會丟數據。隨著系統的服務拓撲從單體應用邁向微服務時代,以及資料庫數量和種類的增長,分布式系統在滿足傳統 ACID 標準的事務性需求上,面臨著新的挑戰。
  • 乾貨:18 張思維導圖,後端技術學習路線長這樣!
    Linux在後臺開發領域,你所能接觸到的後端服務不敢說 100%,至少也有 90% 以上是運行在 Linux 系統之上,因為它開源、便利、功能強大,需要學習以下技術點:Linux系統使用所以如果你想走後端開發這條路線,我建議你趁早使用 Linux
  • Spring全家桶、Dubbo、分布式、消息隊列後端必備全套開源項目
    《Spring Security OAuth2 入門》 對應 lab-68-spring-security-oauth《Spring Security OAuth2 存儲器》 對應 lab-68-spring-security-oauth《Spring Security OAuth2 單點登陸
  • 乾貨:21 張思維導圖,檸檬哥肝了半個月的「後端技術學習路線」長啥樣?
    對於高並發服務必須改變傳統的單進程模型,才能處理的過來如此海量的請求。多進程對於高並發的服務請求,由於後臺服務一般都是 IO 密集型應用,IO 密集型應用就是大部分 CPU 時間用在網絡 IO 上,相對的是 CPU 密集型應用大部分時間花在數據計算上。
  • 分布式光伏如何直面「平價」挑戰?
    「光伏發電成本的不斷下降為分布式光伏規模化發展掃清了道路,越來越多的企業看好分布式光伏的投資價值。在二氧化碳排放力爭2030年前達峰、努力爭取2060年前實現碳中和的目標下,分布式光伏將成為其中不可或缺的重要組成部分。」日前,中國光伏行業協會副秘書長王世江在第四屆分布式光伏嘉年華上表示。
  • SpringCloud:分布式系統面臨的問題及解決方案
    服務雪崩多個微服務之間調用的時候,假設微服務A調用微服務B和微服務C,微服務B和微服務C又調用其它微服務,這就是所謂的「扇出」。如果扇出的鏈路上某個微服務的調用響應時間過長或者不可用,對微服務A的調用就會佔用越來越多的系統資源,進而引起系統崩潰,這就是所謂的「雪崩效應」。
  • IPFS分布式存儲到底有什麼神奇之處?
    IPFS必讀手冊 IPFS的存儲需求和挑戰 IPFS作為分布式存儲的新興場景,與傳統的分布式存儲場景有著較大的區別,主要分為性能、可靠性、容量、供應、價格、易維護性這幾個方面的需求。 性 能 在性能上主要分為三部分挑戰。
  • 實戰|單點登錄系統原理與實現(全套流程圖+源碼)
    整編:微信公眾號,搜雲庫技術團隊,ID:souyunku因此,我們需要一種全新的登錄方式來實現多系統應用群的登錄,這就是單點登錄。三、單點登錄什麼是單點登錄?單點登錄全稱Single Sign On(以下簡稱SSO),是指在多系統應用群中登錄一個系統,便可在其他所有系統中得到授權而無需再次登錄,包括單點登錄與單點註銷兩部分。1、登錄相比於單系統登錄,sso需要一個獨立的認證中心,只有認證中心能接受用戶的用戶名密碼等安全信息,其他系統不提供登錄入口,只接受認證中心的間接授權。
  • Spring Security基於Oauth2的SSO單點登錄怎樣做?一個註解搞定
    本文主要介紹 同域 和 跨域 兩種不同場景單點登錄的實現原理,並使用 Spring Security 來實現一個最簡單的跨域SSO客戶端 。二、原理說明單點登錄主流都是基於共享 cookie 來實現的,下面分別介紹 同域 和 跨域 下的兩種場景具體怎樣實現共享 cookie 的2.1.
  • 這才是分布式系統CAP的正確打開方式!
    並且這本身就違背了我寫作的初衷;加之正好前幾天和同事以ZooKeeper的用戶行為反推了CAP理論,回過頭來細琢磨了下,還蠻有意思的!閒話少絮,我們進入正題!本文宗旨:深入淺出!聊透!「紙面」上的CAP相信很多同學都聽過CAP這個理論,為了避免我們認知不同,我們先來統一下知識起點。CAP理論在1999年一經提出就成為了分布式系統領域的頂級教義。並表明分布式服務中,存在三要素:一致性、可用性、分區容錯性。
  • 【SDCC講師專訪】AdMaster技術副總裁盧億雷:分布式資料庫挑戰與分析
    在大會召開之際,筆者採訪到了AdMaster技術副總裁盧億雷,請他分享分布式資料庫面臨的挑戰,以及怎樣成為一名優秀的技術人?屆時,盧億雷將在新一代資料庫調優實戰論壇中帶來《分布式資料庫挑戰與分析》的主題分享,歡迎前來現場聆聽【點擊這裡搶票】。
  • 分離可組合式存儲系統架構的特點和挑戰
    其一,由於多層結構以及層內排序的特點,鍵值系統往往面臨嚴重的讀寫放大問題,即數據查詢可能需要多層查找,數據寫入引起多次層間數據合併,因此,如何根據數據以及訪問的特徵,設計更高效的存儲結構與索引結構以減少讀寫放大問題,仍是目前的關注點之一,其挑戰與關鍵是在寫入性能、單點查詢性能、範圍查詢性能、存儲容量開銷等多維度之間進行較好的權衡。
  • Springboot之登錄模塊探索(含Token,驗證碼,網絡安全等知識)
    簡介登錄模塊很簡單,前端發送帳號密碼的表單,後端接收驗證後即可~淦!可是我想多了,於是有了以下幾個問題(裡面還包含網絡安全問題):1.登錄時的驗證碼2.自動登錄的實現3.怎麼維護前後端登錄狀態在這和大家分享下我實現此功能的過程,包括一些技術和心得1.登錄時的驗證碼
  • DTCC2020阿里雲李飛飛:雲原生分布式資料庫與數據倉庫系統點亮數據...
    從傳統的大數據處理來看,犧牲部分ACID換來的分布式水平拓展雖然非常好,解決了很多場景下的需求,但是應用對ACID的需求一直存在,即使是分布式並行計算的場景當中,應用對ACID的需求也變得越來越強。挑戰二:對資源的使用方式傳統的馮諾依曼架構下計算和存儲是緊密耦合的,可將多個伺服器通過分布式協議和處理的方式連成一個系統,但是伺服器和伺服器之間、節點和節點之間,分布式事務的協調、分布式查詢的優化,尤其要保證強一致性、強ACID的特性保證的時候,具有非常多的挑戰。
  • 未來就緒,XSKY發布全新下一代分布式文件系統XGFS
    1分布式文件架構,如何和硬體與時俱進?數位化轉型下的軟體定義存儲架構,可以很好的滿足用戶各種需求,如在標準伺服器上的敏捷部署,可靈活擴展,性能和容量隨伺服器節點數增長而線性增長,硬體升級與更換無需跨存儲系統遷移數據,硬體升級換代紅利即時享用,業務層無感知、無影響等。
  • 談數據:微服務環境下,數據如何治理?
    微服務架構有別於更為傳統的單體架構、垂直架構,它的特點是每個核心的功能,都可以作為一項服務,每個服務都有自己的運行環境、資料庫,可以單獨部署和運行,這意味著各項服務在工作(和出現故障)時不會相互影響,從而將單點故障產生的影響降到最低。
  • 華為:實力見證,以軟硬結合引領分布式存儲創新
    2019年中國軟體定義存儲市場報告,華為市場佔有率41.72%近年來華為一直在深耕分布式存儲,這次在2020軟體定義存儲線上峰會上,筆者聽了一場華為存儲的主題演講,看到華為OceanStor分布式存儲為幫助用戶應對海量數據挑戰所展示的思考、決心和實力。
  • 全球分布式算力共享鼻祖尋找外星人近 21 年,一切都是徒勞?
    外星人存在的可能性很大,但人類不應主動尋找他們,真正的挑戰是弄明白外星人長什麼樣。霍金生前曾如是說道。不久前,這個全球規模最大、影響範圍最廣的分布式計算項目官方宣布:從 2020 年 3 月 31 日起,將不再向參與者發放新的計算任務,項目正式進入休眠期。