<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          前端關(guān)于單點(diǎn)登錄的知識

          共 9077字,需瀏覽 19分鐘

           ·

          2020-08-24 16:22

          作者:An_an16347
          原文:https://juejin.im/post/6844903664264413198

          什么是單點(diǎn)登錄

          單點(diǎn)登錄(Single Sign On),簡稱為 SSO,是目前比較流行的企業(yè)業(yè)務(wù)整合的解決方案之一。SSO的定義是在多個(gè)應(yīng)用系統(tǒng)中,用戶只需要登錄一次就可以訪問所有相互信任的應(yīng)用系統(tǒng)。

          SSO一般都需要一個(gè)獨(dú)立的認(rèn)證中心(passport),子系統(tǒng)的登錄均得通過passport,子系統(tǒng)本身將不參與登錄操作,當(dāng)一個(gè)系統(tǒng)成功登錄以后,passport將會頒發(fā)一個(gè)令牌給各個(gè)子系統(tǒng),子系統(tǒng)可以拿著令牌會獲取各自的受保護(hù)資源,為了減少頻繁認(rèn)證,各個(gè)子系統(tǒng)在被passport授權(quán)以后,會建立一個(gè)局部會話,在一定時(shí)間內(nèi)可以無需再次向passport發(fā)起認(rèn)證。

          舉個(gè)例子,比如淘寶、天貓都屬于阿里旗下的產(chǎn)品,當(dāng)用戶登錄淘寶后,再打開天貓,系統(tǒng)便自動幫用戶登錄了天貓,這種現(xiàn)象背后就是用單點(diǎn)登錄實(shí)現(xiàn)的。

          單點(diǎn)登錄流程

          1.登錄
          • 用戶訪問系統(tǒng)1的受保護(hù)資源,系統(tǒng)1發(fā)現(xiàn)用戶未登錄,跳轉(zhuǎn)至sso認(rèn)證中心,并將自己的地址作為參數(shù)
          • sso認(rèn)證中心發(fā)現(xiàn)用戶未登錄,將用戶引導(dǎo)至登錄頁面
          • 用戶輸入用戶名密碼提交登錄申請
          • sso認(rèn)證中心校驗(yàn)用戶信息,創(chuàng)建用戶與sso認(rèn)證中心之間的會話,稱為全局會話,同時(shí)創(chuàng)建授權(quán)令牌
          • sso認(rèn)證中心帶著令牌跳轉(zhuǎn)會最初的請求地址(系統(tǒng)1)
          • 系統(tǒng)1拿到令牌,去sso認(rèn)證中心校驗(yàn)令牌是否有效
          • sso認(rèn)證中心校驗(yàn)令牌,返回有效,注冊系統(tǒng)1
          • 系統(tǒng)1使用該令牌創(chuàng)建與用戶的會話,稱為局部會話,返回受保護(hù)資源
          • 用戶訪問系統(tǒng)2的受保護(hù)資源
          • 系統(tǒng)2發(fā)現(xiàn)用戶未登錄,跳轉(zhuǎn)至sso認(rèn)證中心,并將自己的地址作為參數(shù)
          • sso認(rèn)證中心發(fā)現(xiàn)用戶已登錄,跳轉(zhuǎn)回系統(tǒng)2的地址,并附上令牌
          • 系統(tǒng)2拿到令牌,去sso認(rèn)證中心校驗(yàn)令牌是否有效
          • sso認(rèn)證中心校驗(yàn)令牌,返回有效,注冊系統(tǒng)2
          • 系統(tǒng)2使用該令牌創(chuàng)建與用戶的局部會話,返回受保護(hù)資源

          用戶登錄成功之后,會與sso認(rèn)證中心及各個(gè)子系統(tǒng)建立會話,用戶與sso認(rèn)證中心建立的會話稱為全局會話,用戶與各個(gè)子系統(tǒng)建立的會話稱為局部會話,局部會話建立之后,用戶訪問子系統(tǒng)受保護(hù)資源將不再通過sso認(rèn)證中心,全局會話與局部會話有如下約束關(guān)系

          • 局部會話存在,全局會話一定存在
          • 全局會話存在,局部會話不一定存在
          • 全局會話銷毀,局部會話必須銷毀
          2.注銷

          sso認(rèn)證中心一直監(jiān)聽全局會話的狀態(tài),一旦全局會話銷毀,監(jiān)聽器將通知所有注冊系統(tǒng)執(zhí)行注銷操作。

          • 用戶向系統(tǒng)1發(fā)起注銷請求
          • 系統(tǒng)1根據(jù)用戶與系統(tǒng)1建立的會話id拿到令牌,向sso認(rèn)證中心發(fā)起注銷請求
          • sso認(rèn)證中心校驗(yàn)令牌有效,銷毀全局會話,同時(shí)取出所有用此令牌注冊的系統(tǒng)地址
          • sso認(rèn)證中心向所有注冊系統(tǒng)發(fā)起注銷請求
          • 各注冊系統(tǒng)接收sso認(rèn)證中心的注銷請求,銷毀局部會話
          • sso認(rèn)證中心引導(dǎo)用戶至登錄頁面

          什么是CAS

          CAS是Central Authentication Service的縮寫,中央認(rèn)證服務(wù),一種獨(dú)立開放指令協(xié)議。CAS 是 Yale 大學(xué)發(fā)起的一個(gè)開源項(xiàng)目,旨在為 Web 應(yīng)用系統(tǒng)提供一種可靠的單點(diǎn)登錄方法。CAS 包含兩個(gè)部分:CAS Server 和 CAS Client。CAS Server 需要獨(dú)立部署,主要負(fù)責(zé)對用戶的認(rèn)證工作;CAS Client 負(fù)責(zé)處理對客戶端受保護(hù)資源的訪問請求,需要登錄時(shí),重定向到 CAS Server。

          CAS 最基本的協(xié)議過程:

          CAS Client 與受保護(hù)的客戶端應(yīng)用部署在一起,以 Filter 方式保護(hù)受保護(hù)的資源。對于訪問受保護(hù)資源的每個(gè) Web 請求,CAS Client 會分析該請求的 Http 請求中是否包含 Service Ticket,如果沒有,則說明當(dāng)前用戶尚未登錄,于是將請求重定向到指定好的 CAS Server 登錄地址,并傳遞 Service (也就是要訪問的目的資源地址),以便登錄成功過后轉(zhuǎn)回該地址。用戶在第 3 步中輸入認(rèn)證信息,如果登錄成功,CAS Server 隨機(jī)產(chǎn)生一個(gè)相當(dāng)長度、唯一、不可偽造的 Service Ticket,并緩存以待將來驗(yàn)證,之后系統(tǒng)自動重定向到 Service 所在地址,并為客戶端瀏覽器設(shè)置一個(gè) Ticket Granted Cookie(TGC),CAS Client 在拿到 Service 和新產(chǎn)生的 Ticket 過后,在第 5,6 步中與 CAS Server 進(jìn)行身份核實(shí),以確保 Service Ticket 的合法性。在該協(xié)議中,所有與 CAS 的交互均采用 SSL 協(xié)議,確保,ST 和 TGC 的安全性。協(xié)議工作過程中會有 2 次重定向的過程,但是 CAS Client 與 CAS Server 之間進(jìn)行 Ticket 驗(yàn)證的過程對于用戶是透明的。另外,CAS 協(xié)議中還提供了 Proxy (代理)模式,以適應(yīng)更加高級、復(fù)雜的應(yīng)用場景,具體介紹可以參考 CAS 官方網(wǎng)站上的相關(guān)文檔。

          什么是OAuth2

          OAuth(開放授權(quán))是一個(gè)開放標(biāo)準(zhǔn),允許用戶讓第三方應(yīng)用訪問該用戶在某一網(wǎng)站上存儲的私密的資源(如照片,視頻,聯(lián)系人列表),而無需將用戶名和密碼提供給第三方應(yīng)用。

          通俗說,OAuth就是一種授權(quán)的協(xié)議,只要授權(quán)方和被授權(quán)方遵守這個(gè)協(xié)議去寫代碼提供服務(wù),那雙方就是實(shí)現(xiàn)了OAuth模式。

          詳細(xì)說就是,OAuth在"客戶端"與"服務(wù)提供商"之間,設(shè)置了一個(gè)授權(quán)層(authorization layer)。"客戶端"不能直接登錄"服務(wù)提供商",只能登錄授權(quán)層,以此將用戶與客戶端區(qū)分開來。"客戶端"登錄授權(quán)層所用的令牌(token),與用戶的密碼不同。用戶可以在登錄的時(shí)候,指定授權(quán)層令牌的權(quán)限范圍和有效期。"客戶端"登錄授權(quán)層以后,"服務(wù)提供商"根據(jù)令牌的權(quán)限范圍和有效期,向"客戶端"開放用戶儲存的資料。

          OAuth2是OAuth1.0的下一個(gè)版本,OAuth2關(guān)注客戶端開發(fā)者的簡易性,同時(shí)為Web應(yīng)用,桌面應(yīng)用和手機(jī),和起居室設(shè)備提供專門的認(rèn)證流程。原先的OAuth,會發(fā)行一個(gè) 有效期非常長的token(典型的是一年有效期或者無有效期限制),在OAuth 2.0中,server將發(fā)行一個(gè)短有效期的access token和長生命期的refresh token。這將允許客戶端無需用戶再次操作而獲取一個(gè)新的access token,并且也限制了access token的有效期。

          CAS和OAuth2區(qū)別

          • CAS的單點(diǎn)登錄時(shí)保障客戶端的用戶資源的安全,OAuth2則是保障服務(wù)端的用戶資源的安全;
          • CAS客戶端要獲取的最終信息是,這個(gè)用戶到底有沒有權(quán)限訪問我(CAS客戶端)的資源;oauth2獲取的最終信息是,我(oauth2服務(wù)提供方)的用戶的資源到底能不能讓你(oauth2的客戶端)訪問;
          • CAS的單點(diǎn)登錄,資源都在客戶端這邊,不在CAS的服務(wù)器那一方。用戶在給CAS服務(wù)端提供了用戶名密碼后,作為CAS客戶端并不知道這件事。隨便給客戶端個(gè)ST,那么客戶端是不能確定這個(gè)ST是用戶偽造還是真的有效,所以要拿著這個(gè)ST去服務(wù)端再問一下,這個(gè)用戶給我的是有效的ST還是無效的ST,是有效的我才能讓這個(gè)用戶訪問。
          • OAuth2認(rèn)證,資源都在OAuth2服務(wù)提供者那一方,客戶端是想索取用戶的資源。所以在最安全的模式下,用戶授權(quán)之后,服務(wù)端并不能直接返回token,通過重定向送給客戶端,因?yàn)檫@個(gè)token有可能被黑客截獲,如果黑客截獲了這個(gè)token,那用戶的資源也就暴露在這個(gè)黑客之下了。于是聰明的服務(wù)端發(fā)送了一個(gè)認(rèn)證code給客戶端(通過重定向),客戶端在后臺,通過https的方式,用這個(gè)code,以及另一串客戶端和服務(wù)端預(yù)先商量好的密碼,才能獲取到token和刷新token,這個(gè)過程是非常安全的。如果黑客截獲了code,他沒有那串預(yù)先商量好的密碼,他也是無法獲取token的。這樣oauth2就能保證請求資源這件事,是用戶同意的,客戶端也是被認(rèn)可的,可以放心的把資源發(fā)給這個(gè)客戶端了。
          • CAS登錄和OAuth2在流程上的最大區(qū)別就是,通過ST或者code去認(rèn)證的時(shí)候,需不需要預(yù)先商量好的密碼。
          總結(jié):
          CAS:授權(quán)服務(wù)器,被授權(quán)客戶端
          1. 授權(quán)服務(wù)器(一個(gè))保存了全局的一份session,客戶端(多個(gè))各自保存自己的session;
          2. 客戶端登錄時(shí)判斷自己的session是否已登錄,若未登錄,則(告訴瀏覽器)重定向到授權(quán)服務(wù)器(參數(shù)帶上自己的地址,用于回調(diào));
          3. 授權(quán)服務(wù)器判斷全局的session是否已登錄,若未登錄則定向到登錄頁面,提示用戶登錄,登錄成功后,授權(quán)服務(wù)器重定向到客戶端(參數(shù)帶上ticket【一個(gè)憑證號】);
          4. 客戶端收到ticket后,請求服務(wù)器獲取用戶信息;
          5. 服務(wù)器同意客戶端授權(quán)后,服務(wù)端保存用戶信息至全局session,客戶端將用戶保存至本地session
          OAuth2:主系統(tǒng),授權(quán)系統(tǒng)(給主系統(tǒng)授權(quán)用的,也可以跟主系統(tǒng)是同一個(gè)系統(tǒng)),第三方系統(tǒng)
          1. 第三方系統(tǒng)需要使用主系統(tǒng)的資源,第三方重定向到授權(quán)系統(tǒng);
          2. 根據(jù)不同的授權(quán)方式,授權(quán)系統(tǒng)提示用戶授權(quán);
          3. 用戶授權(quán)后,授權(quán)系統(tǒng)返回一個(gè)授權(quán)憑證(accessToken)給第三方系統(tǒng)【accessToken是有有效期的】;
          4. 第三方使用accessToken訪問主系統(tǒng)資源【accessToken失效后,第三方需重新請求授權(quán)系統(tǒng),以獲取新的accessToken】。

          什么是JWT

          JSON Web Token(JWT)是一個(gè)開放標(biāo)準(zhǔn)(RFC 7519),它定義了一種緊湊且獨(dú)立的方式,可以在各方之間作為JSON對象安全地傳輸信息。此信息可以通過數(shù)字簽名進(jìn)行驗(yàn)證和信任。JWT可以使用秘密(使用HMAC算法)或使用RSA或ECDSA的公鑰/私鑰對進(jìn)行簽名。

          JSON WEB令牌結(jié)構(gòu)由三部分組成:

          • Header(頭部):包括令牌的類型及正在使用的散列算法。
          • Payload(負(fù)載):聲明是關(guān)于實(shí)體(通常是用戶)和其他數(shù)據(jù)的聲明。索賠有三種類型:標(biāo)準(zhǔn)注冊聲明,公共的聲明和私有的聲明。
          • Signature(簽名):必須采用編碼標(biāo)頭,編碼的有效負(fù)載,秘密,標(biāo)頭中指定的算法,并對其進(jìn)行簽名。
          1. 負(fù)載-標(biāo)準(zhǔn)的聲明:
          • iss:JWT簽發(fā)者
          • sub:JWT所面向的用戶
          • aud:接收J(rèn)WT的一方
          • exp:JWT的過期時(shí)間,這個(gè)過期時(shí)間必須要大于簽發(fā)時(shí)間,這是一個(gè)秒數(shù)
          • nbf:定義在什么時(shí)間之前,該JWT都是不可用的
          • iat:JWT的簽發(fā)時(shí)間
          1. 負(fù)載-公共的聲明:可以添加任何信息,一般添加用戶的相關(guān)信息或其他業(yè)務(wù)需要的必要信息,但不建議添加敏感信息,因?yàn)樵摬糠衷诳蛻舳丝山饷堋?/section>
          2. 負(fù)載-私有聲明:提供者和消費(fèi)者所共同定義的聲明,一般不建議存放敏感信息,因?yàn)閎ase64是對稱解密的,意味著該部分信息可以歸類為明文信息。

          創(chuàng)建簽名需要使用編碼后的headerpayload以及一個(gè)秘鑰,使用header中指定簽名算法進(jìn)行簽名。例如如果希望使用HMAC SHA256算法,那么簽名應(yīng)該使用下列方式創(chuàng)建HMACSHA256(base64UrlEncode(header)+"."+base64UrlEncode(payload), secret)簽名用于驗(yàn)證消息的發(fā)送者以及消息是沒有經(jīng)過篡改的。完整的JWT格式輸出是以.分隔的三段Base64編碼, 密鑰secret是保存在服務(wù)端的,服務(wù)端會根據(jù)這個(gè)密鑰進(jìn)行生成token和驗(yàn)證,所以需要保護(hù)好,更多信息請移步官網(wǎng)

          單點(diǎn)登錄關(guān)于前端的部分

          此代碼采用OAuth2。關(guān)于token存儲問題,參考了網(wǎng)上許多教程,大部分都是將token存儲在cookie中,然后將cookie設(shè)為頂級域來解決跨域問題,但我司業(yè)務(wù)需求是某些產(chǎn)品頂級域也各不相同。故實(shí)現(xiàn)思路是將token存儲在localStorage中,然后通過H5的新屬性postMessage來實(shí)現(xiàn)跨域共享,對跨域不了解的可以看我這篇文章。

          實(shí)現(xiàn)思路:當(dāng)用戶訪問公司某系統(tǒng)(如product.html)時(shí),在product中會首先加載一個(gè)iframe,iframe中可以獲取存儲在localStorage中的token,如果沒有取到或token過期,iframe中內(nèi)部將把用戶將重定向到登錄頁,用戶在此頁面登錄,仍將去認(rèn)證系統(tǒng)取得token并保存在iframe頁面的localStorage

                                          

          產(chǎn)品頁面

          登錄

          講解:在product.html中實(shí)例化了ssoAuth后,此頁面便將iframe引入了當(dāng)前頁,名為opts.path的值,即cross_domain.html。auth.getToken()是獲取此iframe頁面中的localStorage值。

              //auth_1.0.0.js    function ssoAuth(opts) {        this._origin = opts.origin,        this._iframe_path = opts.path,        this._iframe = null,        this._iframe_ready = false,        this._queue = [],        this._auth = {},        this._access_token_msg = { type: "get", key: "access_token" },        this._callback = undefined,        that = this;                //判斷是否支持postMessage及l(fā)ocalStorage       var supported = (function () {            try {                return window.postMessage && window.JSON && 'localStorage' in window && window['localStorage'] !== null;            } catch (e) {                return false;            }        })();                _iframeLoaded = function () {            that._iframe_ready = true            if (that._queue.length) {                for (var i = 0, len = that._queue.length; i < len; i++) {                    _sendMessage(that._queue[i]);                }                that._queue = [];            }        }            _sendMessage = function (data) {            // 通過contentWindow屬性,腳本可以訪問iframe元素所包含的HTML頁面的window對象。            that._iframe.contentWindow.postMessage(JSON.stringify(data), that._origin);        }                //獲取token,但因?yàn)榇藭r(shí)iframe還沒有加載完成,先將消息存儲在隊(duì)列_queue中        this._auth.getToken = function (callback) {            that._callback = callback            if (that._access_token_msg && that._iframe_ready) {                //當(dāng)iframe加載完成,給iframe所在的頁面發(fā)送消息                _sendMessage(that._access_token_msg);            } else {                that._queue.push(that._access_token_msg);            }        }            var _handleMessage = function (event) {            if (event.origin === that._origin) {                var data = JSON.parse(event.data);                if (data.error) {                    console.error(event.data)                    that._callback({ value: null });                    return;                }                if (that._callback && typeof that._callback === 'function') {                    that._callback(data);                } else {                    console.error("callback is null or not a function, please ");                }            }        }            this._auth.doWebLogin = function () {            window.location.href = opts.origin + opts.login_path + "?redirect_url=" + window.location.href        }        //初始化了一個(gè)iframe,并追加到父頁面的底部        if (!this._iframe && supported) {            this._iframe = document.createElement("iframe");            this._iframe.style.cssText = "position:absolute;width:1px;height:1px;left:-9999px;";            document.body.appendChild(this._iframe);                if (window.addEventListener) {                this._iframe.addEventListener("load", function () {                    _iframeLoaded();                }, false);                window.addEventListener("message", function (event) {                    _handleMessage(event)                }, false);            } else if (this._iframe.attachEvent) {                this._iframe.attachEvent("onload", function () {                    _iframeLoaded();                }, false);                window.attachEvent("onmessage", function (event) {                    _handleMessage(event)                });            }            this._iframe.src = this._origin + this._iframe_path;        }        return this._auth;    }


                                          

          PS:注銷暫時(shí)沒做。另外postMessage有兼容性問題,如果其它小伙伴有更好的方法,望分享一下,謝謝~

          參考:

          • www.cnblogs.com/ywlaker/p/6…
          • www.ruanyifeng.com/blog/2014/0…
          • www.cnblogs.com/flying607/p…
          • 375287760.iteye.com/blog/240097…

          最后

          1.看到這里了就點(diǎn)個(gè)在看支持下吧,你的在看是我創(chuàng)作的動力。

          2.關(guān)注公眾號程序員成長指北「帶你一起學(xué)Node」

          3.我是kaola?,可以添加我的微信【ikoala520】,拉你進(jìn)技術(shù)交流群一起學(xué)習(xí)。


          點(diǎn)贊、在看、轉(zhuǎn)發(fā)支持作者??


          瀏覽 46
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  2024日韩无码 | 日本婷婷网 | 色九九九九 | 国产Av视奸 | 欧美性爱精品在线 |