整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          單點登錄的CAS實踐

          、在談項目實踐之前,先說兩個概念:

          (1)ruoyi-vue:采用前后端分離的單體web框架,參見介紹 | RuoYi,使用MIT開源協議,對商業使用友好。

          (2)CAS:英文為Central Authentication Service,即中央認證服務,為耶魯大學發起的一個開源項目,是實現sso單點登錄的框架。官網地址:https://www.apereo.org/projects/cas。關于spring secuity集成cas可參考:https://docs.spring.io/spring-security/site/docs/5.4.1/reference/html5/#servlet-cas。

          CAS官方架構:https://apereo.github.io/cas/development/planning/Architecture.html。

          CAS架構圖

          CAS執行邏輯:CAS分CAS Server和CAS Client。其中CAS Server用于分發和驗證tickets,CAS Client從CAS Server檢索授權用戶的身份。

          時序圖參見:https://apereo.github.io/cas/development/protocol/CAS-Protocol.html。

          (1)訪問服務: SSO 客戶端發送請求訪問應用系統。

          (2)定向認證: SSO 客戶端重定向請求到 CAS服務器。

          (3)用戶認證:用戶身份認證。

          (4)發放票據: 成功登錄后,CAS服務器向用戶發放TGT(ticket-granting ticket)全局票據,創建SSO會話。Server端是TGT,Client端是TGC(Ticket Granted Cookie),類似于session和cookie。同時TGT簽發一個ST返回給瀏覽器(如不同應用請求,發現TGC對應了一個TGT,同樣會簽發ST)。

          (5)驗證票據: CAS服務器驗證票據 Service Ticket (ST)的合法性,驗證通過后,允許客戶端訪問服務。ST作為Url中的get參數傳遞。

          (6)傳輸用戶信息:CAS服務器驗證票據通過后,傳輸用戶認證結果信息給客戶端。

          CAS執行邏輯圖

          二、回到正題,如何在ruoyi-vue(3.8.1)項目中集成CAS呢。由于ruoyi-vue基于spring seruity。需集成spring-security-cas依賴。另外認證要增加和CAS服務端的集成。

          本文參考:RuoYi-Vue前后端分離版集成cas_GGX-520的博客-CSDN博客_ruoyi分離版cas

          后端集成:

          1、common模塊添加對CAS的支持。

          <!-- 添加spring security cas支持 -->
          <dependency>
              <groupId>org.springframework.security</groupId>
              <artifactId>spring-security-cas</artifactId>
          </dependency>

          2、配置文件修改

          #CAS
          cas:
            server:
              host:
                #CAS服務地址
                url: http://localhost:8888/cas
                #CAS服務登錄地址
                login_url: ${cas.server.host.url}/login
                #CAS服務登出地址
                logout_url: ${cas.server.host.url}/logout?service=${app.server.host.url}
          # 應用訪問地址
          app:
            #開啟cas
            casEnable: true
            server:
              host:
                url: http://localhost:${server.port}
            #應用登錄地址
            login_url: /
            #應用登出地址
            logout_url: /logout
            #前端登錄地址
            web_url: http://localhost/

          3、修改LoginUser.java

          由于CAS認證需要authorities屬性,在common模塊中直接new HashSet():

          @Override
          public Collection<? extends GrantedAuthority> getAuthorities()
          {
              return new HashSet();
          }

          4、在common模塊中修改Constants.java

          /**
           * CAS登錄成功后的后臺標識
           */
          public static final String CAS_TOKEN = "cas_token";
          
          /**
           * CAS登錄成功后的前臺Cookie的Key
           */
          public static final String WEB_TOKEN_KEY = "Admin-Token";

          5、在framework模塊config.properties下新增CasProperties.java

          CasProperties代碼

          6、在framework模塊web.service下新增CasUserDetailsService.java

          CasUserDetailService代碼

          7、在framework模塊security.handle下添加CasAuthenticationSuccessHandler.java

          CasAuthenticationSuccessHandler代碼

          8、在framework模塊config.SecurityConfig下修改SecurityConfig。(setCasServerUrlPrefix 從cas-client 3.6.0已移除)

          SecurityConfig代碼

          前端集成:

          1、修改settings.js

          settings.js代碼

          2、修改permission.js,判斷沒有token時訪問cas登錄頁面

          permission.js 代碼

          3、修改request.js、Navbar.vue,登出后不做響應

          request.js代碼

          Navbar.vue代碼

          4、修改user.js,登出后跳轉到cas登出頁面

          user.js代碼

          另外CAS Server需另外搭建。地址為:https://github.com/apereo/cas/releases/

          JDK 5之前Java語言是靠synchronized關鍵字保證同步的,這會導致有鎖

          • 鎖機制存在以下問題:

          (1)在多線程競爭下,加鎖、釋放鎖會導致比較多的上下文切換和調度延時,引起性能問題。

          (2)一個線程持有鎖會導致其它所有需要此鎖的線程掛起。

          (3)如果一個優先級高的線程等待一個優先級低的線程釋放鎖會導致優先級倒置,引起性能風險。

          volatile是不錯的機制,但是volatile不能保證原子性。因此對于同步最終還是要回到鎖機制上來。

          獨占鎖是一種悲觀鎖,synchronized就是一種獨占鎖,會導致其它所有需要鎖的線程掛起,等待持有鎖的線程釋放鎖。而另一個更加有效的鎖就是樂觀鎖。所謂樂觀鎖就是,每次不加鎖而是假設沒有沖突而去完成某項操作,如果因為沖突失敗就重試,直到成功為止。樂觀鎖用到的機制就是CAS,Compare and Swap。

          一、什么是CAS

          CAS,compare and swap的縮寫,中文翻譯成比較并交換。

          CAS的語義是“我認為V的值應該為A,如果是,那么將V的值更新為B,否則不修改并告訴V的值實際為多少,”CAS是項樂觀鎖技術,當多個線程嘗試使用CAS同時更新同一個變量時,只有其中一個線程能更新變量的值,而其它線程都失敗,失敗的線程并不會被掛起,而是被告知這次競爭中失敗,并可以再次嘗試。CAS有3個操作數,內存值V,舊的預期值A,要修改的新值B。當且僅當預期值A和內存值V相同時,將內存值V修改為B,否則什么都不做。

          CAS 操作包含三個操作數 —— 內存位置(V)、預期原值(A)和新值(B)。 如果內存位置的值與預期原值相匹配,那么處理器會自動將該位置值更新為新值 。否則,處理器不做任何操作。無論哪種情況,它都會在 CAS 指令之前返回該 位置的值。(在 CAS 的一些特殊情況下將僅返回 CAS 是否成功,而不提取當前 值。)CAS 有效地說明了“我認為位置 V 應該包含值 A;如果包含該值,則將 B 放到這個位置;否則,不要更改該位置,只告訴我這個位置現在的值即可。”

          通常將 CAS 用于同步的方式是從地址 V 讀取值 A,執行多步計算來獲得新 值 B,然后使用 CAS 將 V 的值從 A 改為 B。如果 V 處的值尚未同時更改,則 CAS 操作成功。

          類似于 CAS 的指令允許算法執行讀-修改-寫操作,而無需害怕其他線程同時 修改變量,因為如果其他線程修改變量,那么 CAS 會檢測它(并失敗),算法 可以對該操作重新計算。

          二、CAS的目的

          利用CPU的CAS指令,同時借助JNI來完成Java的非阻塞算法。其它原子操作都是利用類似的特性完成的。而整個J.U.C都是建立在CAS之上的,因此對于synchronized阻塞算法,J.U.C在性能上有了很大的提升。

          三、CAS存在的問題

          CAS雖然很高效的解決原子操作,但是CAS仍然存在三大問題。ABA問題,循環時間長開銷大和只能保證一個共享變量的原子操作

          1. ABA問題。因為CAS需要在操作值的時候檢查下值有沒有發生變化,如果沒有發生變化則更新,但是如果一個值原來是A,變成了B,又變成了A,那么使用CAS進行檢查時會發現它的值沒有發生變化,但是實際上卻變化了。ABA問題的解決思路就是使用版本號。在變量前面追加上版本號,每次變量更新的時候把版本號加一,那么A-B-A 就會變成1A-2B-3A。

          從Java1.5開始JDK的atomic包里提供了一個類AtomicStampedReference來解決ABA問題。這個類的compareAndSet方法作用是首先檢查當前引用是否等于預期引用,并且當前標志是否等于預期標志,如果全部相等,則以原子方式將該引用和該標志的值設置為給定的更新值。

          關于ABA問題參考文檔: http://blog.hesey.net/2011/09/resolve-aba-by-atomicstampedreference.html

          2. 循環時間長開銷大。自旋CAS如果長時間不成功,會給CPU帶來非常大的執行開銷。如果JVM能支持處理器提供的pause指令那么效率會有一定的提升,pause指令有兩個作用,第一它可以延遲流水線執行指令(de-pipeline),使CPU不會消耗過多的執行資源,延遲的時間取決于具體實現的版本,在一些處理器上延遲時間是零。第二它可以避免在退出循環的時候因內存順序沖突(memory order violation)而引起CPU流水線被清空(CPU pipeline flush),從而提高CPU的執行效率。

          3. 只能保證一個共享變量的原子操作。當對一個共享變量執行操作時,我們可以使用循環CAS的方式來保證原子操作,但是對多個共享變量操作時,循環CAS就無法保證操作的原子性,這個時候就可以用鎖,或者有一個取巧的辦法,就是把多個共享變量合并成一個共享變量來操作。比如有兩個共享變量i=2,j=a,合并一下ij=2a,然后用CAS來操作ij。從Java1.5開始JDK提供了AtomicReference類來保證引用對象之間的原子性,你可以把多個變量放在一個對象里來進行CAS操作。

          四、concurrent包的實現

          由于java的CAS同時具有 volatile 讀和volatile寫的內存語義,因此Java線程之間的通信現在有了下面四種方式:

          1. A線程寫volatile變量,隨后B線程讀這個volatile變量。
          2. A線程寫volatile變量,隨后B線程用CAS更新這個volatile變量。
          3. A線程用CAS更新一個volatile變量,隨后B線程用CAS更新這個volatile變量。
          4. A線程用CAS更新一個volatile變量,隨后B線程讀這個volatile變量。

          Java的CAS會使用現代處理器上提供的高效機器級別原子指令,這些原子指令以原子方式對內存執行讀-改-寫操作,這是在多處理器中實現同步的關鍵(從本質上來說,能夠支持原子性讀-改-寫指令的計算機器,是順序計算圖靈機的異步等價機器,因此任何現代的多處理器都會去支持某種能對內存執行原子性讀-改-寫操作的原子指令)。同時,volatile變量的讀/寫和CAS可以實現線程之間的通信。把這些特性整合在一起,就形成了整個concurrent包得以實現的基石。如果我們仔細分析concurrent包的源代碼實現,會發現一個通用化的實現模式:

          1. 首先,聲明共享變量為volatile;
          2. 然后,使用CAS的原子條件更新來實現線程之間的同步;
          3. 同時,配合以volatile的讀/寫和CAS所具有的volatile讀和寫的內存語義來實現線程之間的通信。

          AQS,非阻塞數據結構和原子變量類(java.util.concurrent.atomic包中的類),這些concurrent包中的基礎類都是使用這種模式來實現的,而concurrent包中的高層類又是依賴于這些基礎類來實現的。從整體來看,concurrent包的實現示意圖如下:

          點登錄 (SingleSign-On,SSO) ,是一種幫助用戶快捷訪問網絡中多個站點的安全通信技術。單點登錄系統基于一種安全的通信協議,該協議通過多個系統之間的用戶身份信息的交換來實現單點登錄。使用單點登錄系統時,用戶只需要登錄一次,就可以訪問多個系統,不需要記憶多個口令密碼。

          云程平臺支持CAS、OAuth2、JWT三種主流的單點登錄技術,客戶可根據需求選擇對應技術方案。

          一、CAS總體架構介紹

          CAS(Central Authentication Service)是 Yale大學發起的一個企業級的、開源的項目,旨在為 Web 應用系統提供一種可靠的單點登錄解決方法。CAS的目標是允許用戶訪問多個應用程序只提供一次用戶憑據(如用戶名和密碼)。

          CAS 體系包含兩個部分: CAS Server 和 CAS Client。CAS Server 需要獨立部署,主要負責對用戶的認證工作;CAS Client 負責處理對客戶端受保護資源的訪問請求,需要登錄時,重定向到 CAS Server。

          CAS 具有以下特點:

          • 一個開放的,文檔齊全的協議。
          • 開源的JAVA服務器組件。
          • CAS Client 支持非常多的客戶端(這里指單點登錄系統中的各個 Web 應用),包括 Java, .Net, PHP, Perl, Apache, uPortal, Ruby 等。
          • 文檔社區化和實現的支持。
          • 具有廣泛的客戶群的支持。

          CAS官方文檔:https://apereo.github.io/cas/5.3.x/index.html#

          二、CAS單點原理和集成流程

          在 CAS 的整個登錄過程中,有三個重要的概念。

          1. TGT:TGT 全稱叫做 Ticket Granting Ticket,這個相當于我們平時所見到的 HttpSession 的作用,用戶登錄成功后,用戶的基本信息,如用戶名、登錄有效期等信息,都將存儲在此。
          2. TGC:TGC 全稱叫做 Ticket Granting Cookie,TGC 以 Cookie 的形式保存在瀏覽器中,根據 TGC 可以幫助用戶找到對應的 TGT,所以這個 TGC 有點類似與會話 ID。
          3. ST:ST 全稱是 Service Ticket,這是 CAS Sever 通過 TGT 給用戶發放的一張票據,用戶在訪問其他服務時,發現沒有 Cookie 或者 ST ,那么就會 302 到 CAS Server 獲取 ST,然后會攜帶著 ST 302 回來,CAS Client 則通過 ST 去 CAS Server 上獲取用戶的登錄狀態。

          CAS的單點登錄SSO流程如下, 應用系統要做單點登錄,需要跟CAS服務進行集成,首先要理解CAS集成流程和原理。

          1. 用戶通過瀏覽器訪問應用1,應用1 發現用戶沒有登錄,于是返回 302,并且攜帶上一個 service 參數,讓用戶去 CAS Server 上登錄。
          2. 瀏覽器自動重定向到 CAS Server 上,CAS Server 獲取用戶 Cookie 中攜帶的 TGC,去校驗用戶是否已經登錄,如果已經登錄,則完成身份校驗(此時 CAS Server 可以根據用戶的 TGC 找到 TGT,進而獲取用戶的信息);如果未登錄,則重定向到 CAS Server 的登錄頁面,用戶輸入用戶名/密碼,CAS Server 會生成 TGT,并且根據 TGT 簽發一個 ST,再將 TGC 放在用戶的 Cookie 中,完成身份校驗。
          3. CAS Server 完成身份校驗之后,會將 ST 拼接在 service 中,返回 302,瀏覽器將首先將 TGC 存在 Cookie 中,然后根據 302 的指示,攜帶上 ST 重定向到應用1。
          4. 應用1 收到瀏覽器傳來的 ST 之后,拿去 CAS Server 上校驗,去判斷用戶的登錄狀態,如果用戶登錄合法,CAS Server 就會返回用戶信息給 應用1。
          5. 瀏覽器再去訪問應用2,應用2 發現用戶未登錄,重定向到 CAS Server。
          6. CAS Server 發現此時用戶實際上已經登錄了,于是又重定向回應用2,同時攜帶上 ST。
          7. 應用2 拿著 ST 去 CAS Server 上校驗,獲取用戶的登錄信息。
          8. 在整個登錄過程中,瀏覽器分別和 CAS Server、應用1、應用2 建立了會話,其中,和 CAS Server 建立的會話稱之為全局會話,和應用1、應用2 建立的會話稱之為局部會話;一旦局部會話成功建立,以后用戶再去訪問應用1、應用2 就不會經過 CAS Server 了。

          三、CAS服務端如何部署

          云程平臺對CAS 5.3.x版本無縫集成,并對CAS認證校驗進行了擴展,項目上請使用平臺提供的CAS 5.3.x運行包。運行CAS之前需要在數據庫先執行平臺的腳本,CAS獲取用戶信息需訪問平臺的SYS_USER表。

          1 修改數據庫連接

          打開 cas\WEB-INF\classes\application.properties

          修改如下配置:

          #數據庫配置

          spring.datasource.driver-class-name=com.mysql.jdbc.Driver
          spring.datasource.url=jdbc:mysql://127.0.0.1:3306/yuncheng2021?characterEncoding=UTF-8&useUnicode=true&useSSL=false&zeroDateTimeBehavior=convertToNull&serverTimezone=Asia/Shanghai
          spring.datasource.username=root
          spring.datasource.password=root
          spring.datasource.type=org.apache.commons.dbcp2.BasicDataSource
          spring.jpa.database=mysql
          spring.jpa.show-sql=true
          spring.jpa.hibernate.ddl-auto=update
          spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect

          2 啟動cas

          需要準備tomcat,把cas包放到tomcat/webapps目錄下,在tomcat/bin目錄下執行startup.bat(windows)或startup.sh(linux)。

          啟動成功后訪問cas地址,界面如下圖所示:

          四、云程如何對接CAS

          平臺后端CAS配置

          云程平臺后端已集成CAS代碼,在yml配置文件中配置cas服務地址即可。

          application.yml 進行如下配置:

          #cas單點登錄
          cas:
          prefixUrl: http://cas.example.org:8443/cas

          平臺前端CAS配置

          修改public/config/bootConfig.js

          VUE_APP_SSO設置為true

          VUE_APP_CAS_BASE_URL配置單點登錄服務地址


          主站蜘蛛池模板: 无码中文字幕乱码一区| 亚洲午夜福利AV一区二区无码| 亚洲日韩国产欧美一区二区三区| 亚洲熟妇AV一区二区三区宅男| 久99精品视频在线观看婷亚洲片国产一区一级在线 | 中文字幕无码不卡一区二区三区| 无码一区二区三区老色鬼| 亚洲性日韩精品一区二区三区 | 三上悠亚亚洲一区高清| 无人码一区二区三区视频| 亚洲无人区一区二区三区| 国产一区二区三区不卡观| 高清一区二区三区免费视频| 91精品福利一区二区三区野战| 国产香蕉一区二区三区在线视频 | 日韩人妻精品无码一区二区三区| 99热门精品一区二区三区无码 | 久久精品国产亚洲一区二区三区 | 亚洲国产av一区二区三区| 中文字幕AV一区二区三区 | 精品国产区一区二区三区在线观看 | 国产精品合集一区二区三区 | 久久无码人妻精品一区二区三区| 亚洲AV日韩AV天堂一区二区三区| 精品人妻AV一区二区三区| 国产中的精品一区的| 无码人妻久久一区二区三区蜜桃 | 国产美女口爆吞精一区二区| 激情内射亚洲一区二区三区| 波多野结衣中文字幕一区二区三区| 波多野结衣免费一区视频| 国产对白精品刺激一区二区| 乱人伦一区二区三区| 精品无码一区二区三区爱欲 | 无码人妻少妇色欲AV一区二区| 成人精品一区二区三区电影| 国产美女精品一区二区三区| 国精产品一区一区三区MBA下载| 国产乱码一区二区三区爽爽爽| 中文字幕一区在线观看视频| 中文人妻无码一区二区三区|