單點登錄詳解(token簡述)(七)


前言

為什么整理單點登錄?

主要的原因還是自己以前學習的時候曾經用過,但是時間太久,忘記了里面用到了哪些技術、及如何實現的,每次想到單點登錄總是感覺即會又不會,這次整理session時,又涉及到了單點登錄,而且單點登錄里面還用到了redis,也是我這次要整理的內容,故而單獨把單點登錄抽出來,系統的梳理下,以備下次忘記時重溫。

順便也把以前學習分布式項目中用到的相關技術:double、zookeeper等統一梳理一遍,加強對現在項目的整理架構的理解。

其實,無論是單一的應用,還是分布式項目乃至現在的微服務技術,其實說到底,思想都是相通的,技術也是相通,只有從底層了解始末,融匯貫通,才會對技術的整體有一個把控,不至於迷失在技術進步的潮流中。       

一、什么是單點登錄

 SSO(Single Sign On)單點登錄是實現多個系統之間統一登錄的驗證系統,簡單來說就是:有A,B,C三個系統,在A處登錄過后,再訪問B系統,B系統就已經處於了登錄狀態,C系統也是一樣。舉個生活中栗子:你同時打開天貓和淘寶,都進入login界面,都要求你登錄的,現在你在淘寶處登錄后,直接在天貓處刷新,你會發現,你已經登錄了,而且就是你在淘寶上登錄的用戶。說明他們實現了SSO,並且持有相同的信息。

二、為什么要用到單點登錄

一次登錄,多處使用。

三、單點登錄的實現

3.1自己什么時候用過單點登錄

培訓時,做的ego項目里搭建過一個單點登錄的子系統。說白了,就是類似於京東、淘寶這樣的一個電商項目。因為采用的是分布式項目結構,各個模塊分別是一個單獨的應用,分屬不同的服務器,想要實現一處登錄,多處使用,肯定不能再用session了。

3.2 實現思路

我們這里的實現思路如下:

Redis+Cookie實現模擬Session功能,實現登錄功能。

  • 適應場景 :分布式系統中,才會使用單點登錄!
  • 說明:在分布式項目中,一次登錄,項目之間共享登錄狀態。
  • 思路:
    • 單獨有一個登錄(還包含注冊等)項目;
    • 所有其他項目需要登錄,或需要使用用戶登錄后狀態都向登錄項目進行請求。

3.3為什么不能用session與cookie實現

1、跨服務器了,所以不能用session;

2、cookie的話,是存放在瀏覽器端的,不安全;而且用戶也可以禁用cookie(這里指的是存放在本地的cookie,不是會話cookie)。

3、放到注冊中心,zookeeper:不行,如果掛了就不知道用戶是否登錄了。(聯想到了dubbo的健壯性)

 

 4、放到redis里,redis可以搞集群,一個宕機了也沒事。

3.3 代碼

1、關於代碼不再進行copy,相關的具體實現已經看過代碼及視頻了,這里只對實現的思路及過程進行說明。

2、思路

1.用戶登錄
    1.1 用戶登錄的時候,向cookie中添加了一個TT_TOKEN值。
    1.2 同時,還需要向redis中添加一個user對象  key = user:token value = user對象的json字符串
2.一處登錄多處使用    
    2.1 每個頁面加載的時候,需要check。當前Cookie[TT_TOKEN]中是否有值
    2.2 如果有TT_TOKEN,從redis中將對象取出來!
3.退出的時候:
    3.1 刪除cookie 中 TT_TOKEN
    3.2 刪除redis中的值!

詳細的代碼參看下面的部分主要代碼。

3、發送請求時相關參數,可以看到有cookie信息。

4、redis存的用戶信息

3.3.1 登錄功能

登錄的功能是在一個單獨的項目ego1-passport中實現的。

具體步驟

1.    需求分析:將登錄的信息存放到redis中,目的是想做sso!
1.1 登錄控制器接收接收兩個參數username和password
1.2 調用Dubbo服務判斷用戶是否登錄成功.
1.3 產生Cookie,存放UUID
1.4 把用戶信息放入到Redis中.
1.5     從哪里跳轉到登錄頁面,再跳轉回去那個頁面.
2.    實現過程,新建一個項目ego-passport,選擇war類型。
3.    導入相關的配置文件。Pom.xml,web.xml,spring相關配置文件。

詳細代碼可以看筆記、視頻去。

1、登錄方法部分代碼

@Value("${redis.user.key}")
    private String key; @Override public EgoResult login(TbUser user, HttpServletRequest request, HttpServletResponse response) { EgoResult er = new EgoResult(); // 根據數據庫查詢,查詢出來之后,需要放到Redis中 TbUser user2 = tbUserDubboService.selByUser(user); if (user2!=null) { String uuid = UUID.randomUUID().toString();  // cookieName 是根據前台js來確定。 CookieUtils.setCookie(request, response, "TT_TOKEN", uuid); // 需要存儲到redis 中 key組成是由key+uuid user:uuid user:65bedb06-9931-4fe8-9eb7-7fe1f8846d0b // value:實體類對象登錄對象 jedisPoolDaoImpl.set(key+uuid, JsonUtils.objectToJson(user2)); // 返回值是根據易購商城接口sso登錄來確定 er.setMsg("OK"); er.setStatus(200); } return er; }

可以看出來,在登錄時,實現了如下操作:

  • 先查庫,看有沒有這個用戶;
  • 用戶存在的話,會在cookie里添加新值,key為token(這里命名為TT_TOKEN),value為uuid。
  • 將用戶信息放在redis中,key為user:uuid,value為用戶對象轉譯的json串。

為什么會用到cookie?

如下截圖,其他服務頁面在訪問時,會通過cookie,獲取token,來校驗,如果不存在token的話,會返回,跳轉到登錄界面。

 

 需要理解到的是,這里的cookie是一個會話cookie。

為什么要用token?

校驗用戶是否登錄;

通過token,從redis中獲取用戶信息;

說白了,token就相當於一張通票,一處登陸(相當於買了一張通票,有了它,各個分園都可以去),處處使用(各個服務器都無需再次登錄,並且可以通過token去redis中獲取到用戶信息)。

token是什么?

在下面的延伸里有說明。其實,這里的token值,就是自己編寫的一個隨機uuid,然后放到了cookie中。它在這個分布式項目中就是起到了一個唯一標識並記錄(存在cookie里了)用戶信息的作用。是用戶登錄的憑證。

1、用戶登錄的請求及返回信息簡略

3.3.2 在ego-portal中當用戶登錄成功后,在最上面顯示用戶信息

通過token,從redis中獲取用戶信息。

請求及返回參數示例:

3.3.3 退出功能

刪除redis,同時刪除cookie。

關於sso的介紹與使用,也可以參考下面的鏈接:https://blog.csdn.net/zhangjingao/article/details/81735041

四、延伸

4.1 復習HttpSession和Cookie

4.1.1 HttpSession

2.1 session中文名稱:會話.瀏覽器開啟到關閉的這段時間!

2.2 如何產生的?

2.2.1 在request.getSession();才能產生Session,產生完成后占用系統內存的.

2.3  Session原理.

1、創建Session的時候,服務器將生成一個唯一的sessionid然后用它生成一個關閉瀏覽器就會失效的cookie[JSESSIONID是cookie產生]。

 

2、然后再將一個與這個sessionid關聯的數據項加入散列表。

    例如這樣一段代碼:Session["UserName"]=23;

    假設sessionid為123那么散列表中會追加一行

     sessionid          username

     123                  23

 

3、當瀏覽器端提交到服務器時,會通過sessionid=123去散列表中尋找屬於該用戶的Session信息。

4.1.2 cookie

1.1 解釋:客戶端存值技術。

1.1.1 存儲位置:內容存放在客戶端瀏覽器中。

1.1.2 可以存儲什么類型的值:只能存儲文本數據(字符串)。

1.2 Cookie流程

1.2.1 步驟1: 客戶端向服務器端發送請求時,瀏覽器會自動攜帶所有能獲取的Cookie內容.放在請求對象中。

1.2.2 步驟2:所有Cookie產生位置都是服務器端.在服務器端可以創建任意和key-value形式的Cookie對象.並把cookie對象放入到response對象中。

1.2.2.1 在servlet或jsp腳本中Cookie c=new Cookie(“”,””)。

1.2.2.2服務器端通過request.getCookies()獲取cookie。

1.2.3 步驟3:把Cookie響應給客戶端(重定向)。

1.2.4 步驟4:瀏覽器接收到響應后,會從響應對象中獲取到Cookie內容,並把Cookie內容存儲在指定位置。

1.3Cookie幾個概念。

1.3.1 有效時間:

1.3.1.1 默認與Session對象有效時間相同.

1.3.1.2 手動設置Cookie有效時間,固定有效時間.不刷新

//有效時間秒
 c.setMaxAge(10);

1.3.2 可訪問路徑問題.

1.3.2.1 設置完成后cookie只能被當前目錄及子目錄進行訪問。

/cookie/jsp/ : cookie表示項目名稱jsp表示在WebContent目錄下的文件夾

c.setPath("/cookie/jsp/");

1.3.3 設置可訪問域名問題。

 //防止其他網站獲取cookie內容

     c.setDomain("localhost");

案例:

@WebServlet("/TCookie")
public class TCookie extends HttpServlet {
    private static final long serialVersionUID = 1L;

    // servlet : 中核心方法:service() 方法是處理請求的method="post/get"。
    // 如果請求的是get,則會有service()方法,將請求發送給doGet()方法處理,post---doPost();
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // 1.創建cookie
        Cookie cookie = new Cookie("name", "admin");

        // 設置cookie 的生命周期
        // cookie.setMaxAge(10);
        // 設置一個訪問路徑
        // cookie.setPath("/testcookie/jsp/");
        // 設置一個域名方法
        cookie.setDomain("localhost");
        // 2.將cookie添加到response中
        response.addCookie(cookie);
        // 3.將cookie發送到客戶端
        response.sendRedirect("index.jsp");
    }
}

前端:

/testcookie/jsp/index1.jsp
<body>
<h1>index1 ------------</h1>
    <!-- 取cookie -->
    <!-- 使用小腳本來取得cookie對象 -->
    <%
    /* 數組定義:  數據類型 [] 數組名稱 = new 數據類型[長度] 基本數據類型,引用數據類型 */
        Cookie [] c = request.getCookies();    
        /* 增強for循環 for(數據類型 變量名 : 數組/集合){} */
        for(Cookie cookie:c){
            /* jsp九大內置對象。誰是輸出out */
            out.println(cookie.getName()+"======"+cookie.getValue()+"<br/>");
        }
    %>
</body>

4.2 token

 令牌。
在計算機身份認證中是令牌(臨時)的意思,在詞法分析中是標記的意思。一般作為邀請、登錄系統使用。

token是計算機術語:令牌,令牌是一種能夠控制站點占有媒體的特殊幀,以區別數據幀及其他控制幀。token其實說的更通俗點可以叫暗號,在一些數據傳輸之前,要先進行暗號的核對,不同的暗號被授權不同的數據操作。基於 Token 的身份驗證方法

使用基於 Token 的身份驗證方法,在服務端不需要存儲用戶的登錄記錄。大概的流程是這樣的:

1.客戶端使用用戶名跟密碼請求登錄

2.服務端收到請求,去驗證用戶名與密碼

3.驗證成功后,服務端會簽發一個 Token,再把這個 Token 發送給客戶端

4.客戶端收到 Token 以后可以把它存儲起來,比如放在 Cookie 里或者 Local Storage 里

5.客戶端每次向服務端請求資源的時候需要帶着服務端簽發的 Token

6.服務端收到請求,然后去驗證客戶端請求里面帶着的 Token,如果驗證成功,就向客戶端返回請求的數據


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM