天天看點

8、單點登入原理

前言

主要是看圖,其實很詳細的

相同域名下實作單點登入太簡單,因為A系統和B系統域名相同,在通路A時候登入過,在通路B時,由于域名相同,浏覽器會帶上cookies,cookies裡有票據資訊,通路B自然就不用再登入了。

可是如果A系統和B系統域名不同,CAS是怎樣做到已經在通路A系統時候登入過,在通路B系統時就不用再重新登入了呢?此時通路B系統,因為域名不同的緣故,浏覽器沒有帶上存儲有票據資訊的cookies啊,好了此時CAS實作單點登入的原理是這樣的,請看圖:

8、單點登入原理
下面二者具體看代碼
•  TGT(Ticket Grangting Ticket)
        TGT是CAS為使用者簽發的登入票據,擁有了TGT,使用者就可以證明自己在CAS成功登入過。TGT封裝了Cookie值以及此Cookie值對應的使用者資訊。
        使用者在CAS認證成功後,CAS生成cookie(叫TGC),寫入浏覽器,同時生成一個TGT對象,放入自己的緩存,TGT對象的ID就是cookie的值。
        當HTTP再次請求到來時,如果傳過來的有CAS生成的cookie,則CAS以此cookie值為key查詢緩存中有無TGT ,如果有的話,則說明使用者之前登入過,如果沒有,則使用者需要重新登入。
•  ST(Service Ticket)
        ST是CAS為使用者簽發的通路某一service的票據。使用者通路service時,service發現使用者沒有ST,則要求使用者去CAS擷取ST。使用者向CAS發出擷取ST的請求,如果使用者的請求中包含cookie,則CAS會以此cookie值為key查詢緩存中有無TGT,如果存在TGT,則用此TGT簽發一個ST,傳回給使用者。使用者憑借ST去通路service,service拿ST去CAS驗證,驗證通過後,允許使用者通路資源。



1)使用者通路cas-client,被攔截跳轉到cas-server進行登入,輸入正确的使用者資訊
2)登入成功後,cas-server簽發一個TGC票據,寫入浏覽器同時生成一個TGT對象,放入自己的緩存,TGT對象的ID就是cookie的值,并再次跳轉到cas-client,同時攜帶着ST票據
cas-client發現有ST票據則拿着ST票據去cas-server驗證,如果驗證通過,則傳回使用者名資訊
3)cas-client登入成功,使用者通路另一個cas-client2時,也會被攔截再次跳轉到cas-server發現TGC票據生成的TGT對象的ID值存在則直接驗證通過,簽發一個ST票據給cas-client2。

           

TGT cookie 存儲在關于伺服器域名的cookie

[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-VwlzeZYR-1587530526192)(markdownImage/[email protected])]

1、問:系統A是如何發現該請求需要登入重定向到認證中心的?

答:使用者通過浏覽器位址欄通路系統A,系統A(也可以稱為CAS用戶端)去Cookie中拿JSESSION,即在Cookie中維護的目前回話session的id,如果拿到了,說明使用者已經登入,如果未拿到,說明使用者未登入。

           

2、問:系統A重定向到認證中心,發送了什麼資訊或者位址變成了什麼?

答:假如系統A的位址為http://a:8080/,CAS認證中心的服務位址為http://cas.server:8080/,那麼重點向前後位址變化為:http://a:8080/————>ttp://cas.server:8080/?service=http://a:8080/,由此可知,重點向到認證中心,認證中心拿到了目前通路用戶端的位址。

           

3、問:登入成功後,認證中心重定向請求到系統A,認證通過令牌是如何附加發送給系統A的?

答:重定向之後的位址欄變成:http://a:8080/?ticket=ST-XXXX-XXX,将票據以ticket為參數名的方式通過位址欄發送給系統A
           

4、問:系統A驗證令牌,怎樣操作證明使用者登入的?

答:系統A通過位址欄擷取ticket的參數值ST票據,然後從背景将ST發送給CAS server認證中心驗證,驗證ST有效後,CAS server傳回目前使用者登入的相關資訊,系統A接收到傳回的使用者資訊,并為該使用者建立session會話,會話id由cookie維護,來證明其已登入。

           

5、問:登入B系統,認證中心是如何判斷使用者已經登入的?

答:在系統A登入成功後,使用者和認證中心之間建立起了全局會話,這個全局會話就是TGT(Ticket Granting Ticket),TGT位于CAS伺服器端,TGT并沒有放在Session中,也就是說,CAS全局會話的實作并沒有直接使用Session機制,而是利用了Cookie自己實作的,這個Cookie叫做TGC(Ticket Granting Cookie),它存放了TGT的id,儲存在使用者浏覽器上。 

使用者發送登入系統B的請求,首先會去Cookie中拿JSESSION,因為系統B并未登入過,session會話還未建立,JSESSION的值是拿不到的,然後将請求重定向到CAS認證中心,CAS認證中心先去使用者浏覽器中拿TGC的值(使用者已經登入過),也就是全局會話id,如果存在則代表使用者在認證中心已經登入,附帶上認證令牌重定向到系統B。
上面登入狀态判斷也是這個邏輯。
           

6、問:登出的過程,各個系統對目前使用者都做了什麼

答:認證中心清除目前使用者的全局會話TGT,同時清掉cookie中TGT的id:TGC; 
然後是各個用戶端系統,比如系統A、系統B,清除局部會話session,同時清掉cookie中session會話id:jsession

           

1、基本概念 、cookie, session, 會話cookie, jssessionid

  • cookie 和 session機制都是為了解決HTTP協定的無狀态性而生的
  • cookie 是用戶端儲存使用者資訊的機制
  • session 是伺服器端儲存使用者資訊的機制
  • cookie其實就是儲存在浏覽器中的一小段文本,當浏覽器第一次通路jsp時,jsp response會給浏覽器生成一個cookie,然後浏覽器會存儲它
  • cookie 具有不可跨域性
  • cookie 和session 聯合使用可以解決跨域記錄使用者資訊的問題
  • 為了使浏覽器記住伺服器上的session,浏覽器會生成一個id , 這個id就叫做jsessionid
  • 另外,由于一些浏覽器禁用cookie, Java EE标準 退出了URL重寫,使url裡面記錄jssessionid、單點的機率的jsessionid是存在單點登入伺服器端的
  • 上述讓浏覽器記住伺服器上的session的形式就叫做會話cookie,會話cookie在使用者登出或者浏覽器關閉後自動删除,這樣就叫做一次會話。

了解了上面的基本概念和标準,對于了解cas的實作和基本流程很有幫助,cas這樣的sso解決方案本來就是建構在cookie和session标準之上的。

1.1、從cookie中擷取jssensionid

Cookie[] cookies = request.getCookies();
for(Cookie cookie:cookies){
    if(cookie.getName().equals("JSESSIONID")){
        log.info("cookie:"+cookie.getName()+"value:"+cookie.getValue());
        loginResultData.setJSESSIONID(cookie.getValue());
    }
}

cookieName:JSESSIONID-value:E5E7A0895E652C49CE066220680E243E
 
           

1.2.1、擷取session

根據結果很明顯我們可以看session中存放的是單點登入攜帶的資訊

//擷取session
HttpSession session   =   request.getSession();
// 擷取session中所有的鍵值
Enumeration<String> attrs = session.getAttributeNames();
    // 周遊attrs中的
while(attrs.hasMoreElements()){
    // 擷取session鍵值
    String name = attrs.nextElement().toString();
    // 根據鍵值取session中的值
    Object vakue = session.getAttribute(name);
    // 列印結果
    System.out.println("------" + name + ":" + vakue +"--------\n");
}

sessionName::_const_cas_assertion_-value:[email protected]

           

1.2.2、從session中擷取資訊

Assertion assertion = session != null ? (Assertion) session.getAttribute(AbstractCasFilter.CONST_CAS_ASSERTION):null;

// 判斷是否登入過,如果已經登入過,進入if并且退出
if (assertion != null){
    log.info("session中擷取的"+assertion.getPrincipal().toString());
}

session中擷取的[email protected]

           

2、用戶端驗證是否登入

)
    @ResponseBody
    @GetMapping(value = "healerjean/validate",produces="application/json;charset=utf-8" )
    public ResponseBean invalidate(HttpServletRequest request){


            Cookie[] cookies = request.getCookies();
            String  JSESSIONID = null;
            String loginSessionId = null ;
            for(Cookie cookie:cookies){
                if(cookie.getName().equals("JSESSIONID")){
                    JSESSIONID = cookie.getValue();
                }
                if(cookie.getName().equals("loginSessionId")){
                    loginSessionId = cookie.getValue();
                }
            }


            LoginResultData loginResultData = new LoginResultData() ;
            if(StringUtils.isNotBlank(JSESSIONID)&&StringUtils.isNotBlank(loginSessionId)&&StringUtils.equals(JSESSIONID,loginSessionId )){

                loginResultData.setJSESSIONID(JSESSIONID);

                return ResponseBean.buildSuccess(loginResultData);

            }


        return ResponseBean.buildFailure("401","未認證,請重新登入");
    }



@Value("${server.login.redirect.url}")
private String server_login_redirect_url;
/**
 * 首頁面進入之後,跳轉到前端url界面,如果是前後端分離用的兩個域名的情況下
 * @return
 */
@GetMapping(value = {"/",""} )
public String loginDev(HttpServletRequest request,HttpServletResponse response){

    Cookie cookieLogin = new Cookie("loginSessionId", getJsessionId(request));
    cookieLogin.setComment("存儲用戶端登入狀态,防止伺服器重新開機之後,session自動重新整理");    // Cookie描述
    cookieLogin.setMaxAge(24*60*60);            // Cookie有效時間 24小時
    response.addCookie(cookieLogin); //給用戶端添加cookie

    return  "redirect://"+server_login_redirect_url;
}


public String getJsessionId(HttpServletRequest request){
    Cookie[] cookies = request.getCookies();
    for(Cookie cookie:cookies){
        if(cookie.getName().equals("JSESSIONID")){
            return cookie.getValue();
        }
    }
    return  null ;
}



           
8、單點登入原理

繼續閱讀