<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      會話跟蹤方案

      Cookie

      什么是Cookie?

      • 概念:存儲在用戶瀏覽器端的一個小型數據文件,用于跟蹤和保存用戶的狀態信息
      • 用處:主要用于保持用戶登錄狀態、跟蹤用戶行為、存儲用戶偏好等
      • 存儲在瀏覽器端

      優點:

      HTTP協議中支持的技術

      缺點

      • 移動端無法使用
      • 不安全,用戶可以自己禁用Cookie
      • Cookie 不能跨域

      跨域區分三個維度:協議、IP/域名、端口

      img

      每個域下面都有各自的 Cookie,訪問不同的網站帶屬于這個網站的Cookie,不會帶別人的 Cookie,否則就會亂套了,前后端也是一樣,瀏覽器會發送請求并且該請求攜帶Cookie到前端,而這個Cookie如果拿去訪問后端就不可行,因為Cookie不能跨域

      問題:但是 Cookie 是明文存儲在用戶本地,而且帶有大量的用戶信息,這不太安全

      相關代碼實踐

      // 設置 Cookie
      @GetMapping("/c1")
      public BaseResponse cookie1(HttpServletResponse response) {
          response.addCookie(new Cookie("loginUser", "lantz"));
          return ResultUtils.success("ok");
      }
      
      // 獲取 Cookie
      @GetMapping("/c2")
      public BaseResponse cookie2(HttpServletRequest request) {
          Cookie[] cookies = request.getCookies();
          for (Cookie cookie : cookies) {
              if (cookie.getName().equals("loginUser")) {
                  log.info("loginUser value=" + cookie.getValue());
              }
          }
          return ResultUtils.success("ok");
      }
      

      在測試c2接口的時候可以看到debug窗口會返回一條數據:

      2025-10-12 18:23:29.206  INFO 37868 --- [nio-8080-exec-5] c.l.l.controller.SessionController       : loginUser value=lantz
      

      說明已經成功獲取Cookie

      Session

      什么是 Session?

      • 概念服務器端保存用戶狀態的機制,每個用戶會話都有一個唯一的 SessionIDJSESSIONID
      • 用處:主要用于跟蹤用戶在服務器上的狀態信息,例如登錄狀態和購物車內容
      • 存儲在服務器端,然后對應的 Session ID 通過 Cookie 保存在客戶端瀏覽器中

      img

      關于 Session

      Session就解決了 Cookie 的這個問題:Cookie 是明文存儲在用戶本地,而且帶有大量的用戶信息,不太安全

      Session 就是把用戶的會話信息存儲在服務端,然后頒發給客戶端一個 sessionId,讓客戶端之后帶著 sessionId 來請求。這樣服務端就可以通過 sessionId 去找到這個用戶的信息,從而識別請求。

      那么客戶端是如何帶上 sessionId 的?

      這個 sessionId 還是按照 Cookie 的形式存儲在用戶的本地,發起請求的時候帶上即可。

      演示代碼

      設置Session

      // 設置 Session
      @GetMapping("/s1")
      public BaseResponse session1(HttpSession session) {
          log.info("HttpSession-s1: {}", session.hashCode());
          session.setAttribute("loginUser", "lantz");
          return ResultUtils.success("ok");
      }
      

      測試s1設置session并且輸出當前Session的哈希碼

      如下所示:

      HttpSession-s1: 2054650805
      

      返回的Cookie

      img

      可見:在發送Session請求的時候,瀏覽器會為當前的請求自動生成一個哈希碼,用作JSESSIONID,并且會將這個JSESSIONID加到Cookie上,一并返回給服務端

      獲取Session

      // 獲取 Session
      @GetMapping("/s2")
      public BaseResponse session2(HttpServletRequest request) {
          HttpSession session = request.getSession();
          log.info("HttpSession-s2: {}", session.hashCode());
          Object loginUser = session.getAttribute("loginUser");
          log.info("loginUser: {}", loginUser);
          return ResultUtils.success("ok");
      }
      

      測試s2獲取到當前Session的哈希碼

      如下所示:

      2025-10-12 18:40:43.562  INFO 16300 --- [nio-8080-exec-4] c.l.l.controller.SessionController       : HttpSession-s2: 2054650805
      2025-10-12 18:40:43.562  INFO 16300 --- [nio-8080-exec-4] c.l.l.controller.SessionController       : loginUser: lantz
      

      Cookie 展示:

      img

      Token

      什么是Token

      • 概念:本質是一個加密的字符串,用于身份驗證和授權,可以包含用戶信息和權限,用于驗證用戶身份或授權訪問資源。
      • 認證后,后端服務會返回 Token,存儲在客戶端(瀏覽器或移動應用中),后續客戶端訪問服務端需要帶上這個 Token

      其實只需要一個能代表身份的憑證即可,一個服務端頒發給用戶的憑證,之后的請求讓用戶帶著這個憑證就行。

      就像我們的身份證代表著我們,里面包含了我們的信息

      但是擔心憑證被偽造怎么辦?可以把憑證給簽名了,這樣服務器就可驗證憑證的真偽了。

      這個憑證就叫 **Token**

      如果一個用戶登陸了系統,就返回一個 Token 給他,之后每次請求他帶這個 Token 來就行。服務器驗證了真偽之后拿到 Token 里面的用戶信息就知道這個請求是誰發的了。

      Token 簡單地說就是一個含有憑證信息的令牌,只要服務器能識別這個令牌就能根據令牌的身份進行相應的相應。

      jwt

      全稱: JSON Web Token(https://jwt.io/)

      定義了一種簡潔的、自包含的格式,用于在通信雙方以json數據格式安全的傳輸信息。由于數字簽名的存在,這些信息是可靠的。

      組成:

      • 第一部分:Header(頭),記錄令牌類型、簽名算法等。例如:
      • 第二部分:Payload(有效載荷),攜帶一些自定義信息、默認信息等。例如:
      • 第三部分:Signature(簽名),防止Token被篡改、確保安全性。將header、payload,并加入指定秘鑰,通過指定簽名算法計算而來。

      代碼演示

      生成令牌

      @Test
      public void getjwt(){
          Map<String, Object> claims = new HashMap<>();
          claims.put("id", 123);
          claims.put("username", "lantz");
          String jwt = Jwts.builder()
              .setClaims(claims) // 自定義載荷
              .signWith(SignatureAlgorithm.HS256, "lanuc") // 簽名算法
              .setExpiration(new Date(System.currentTimeMillis() + 3600 * 100)) // 設置過期時間
              .compact();
          System.out.println(jwt);
      }
      

      生成令牌如下:

      eyJhbGciOiJIUzI1NiJ9.eyJpZCI6MTIzLCJleHAiOjE3NjAyNjc5NDQsInVzZXJuYW1lIjoibGFudHoifQ.9RYwpzNji9kfg33ge1qQUDFq_2vQdO__mr1Eze-IXlc
      

      解析令牌

      @Test
      public void deCode(){
          Claims body = Jwts.parser()
                  .setSigningKey("lanuc") // 指定簽名秘鑰
                  .parseClaimsJws("eyJhbGciOiJIUzI1NiJ9.eyJpZCI6MTIzLCJleHAiOjE3NjAyNjc5NDQsInVzZXJuYW1lIjoibGFudHoifQ.9RYwpzNji9kfg33ge1qQUDFq_2vQdO__mr1Eze-IXlc")//解析令牌
                  .getBody();
          System.out.println(body);
      
      }
      

      生成結果:

      {id=123, exp=1760267944, username=lantz}
      

      SpringBoot 實現

      JwtUtils

      jwt工具類(JwtUtils)-- 生成令牌,解析令牌

      生成令牌

      /**
       * 生成令牌
       * @param claims JWT 第二部分負載 payload 中存儲的內容
       * @return
       */
      public static String generateToken(Map<String, Object> claims) {
      
          return Jwts.builder()
                  .setClaims(claims)
                  .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION))
                  .signWith(SignatureAlgorithm.HS256, SECRET_KEY)
                  .compact();
      }
      

      解析令牌

      /**
       * 解析JWT Token
       * @param token jwt 令牌
       * @return
       */
      public static Claims parseToken(String token) {
          return Jwts.parser()
                  .setSigningKey(SECRET_KEY)
                  .parseClaimsJws(token)
                  .getBody();
      }
      

      用戶登錄

      需要先獲取用戶登錄信息,然后才能根據用戶信息生成令牌

      @PostMapping("/login")
      public BaseResponse<LoginResponse> userLogin(@RequestBody UseLoginRequest useLoginRequest, HttpServletRequest request){
          if (useLoginRequest == null){
              return null;
          }
          String userAccount = useLoginRequest.getUserAccount();
          String userPassword = useLoginRequest.getUserPassword();
          if (StringUtils.isAnyBlank(userAccount, userPassword)) {
              return null;
          }
          User user = userService.userLogin(userAccount, userPassword, request);
          if (user == null) {
              return ResultUtils.error(ErrorCode.PARAMS_ERROR, "登錄失敗");
          }
          // 獲取登錄用戶
          User loginUer = userService.getLoginUer(request);
          // 生成令牌,下發令牌
          Map<String, Object> claims = new HashMap<>();
          claims.put("id", loginUer.getId());
          claims.put("userAccount", loginUer.getUserAccount());
          claims.put("userName", loginUer.getUserName());
          String jwt = JwtUtils.generateToken(claims); // 生成令牌
          
          // 創建登錄響應
          LoginResponse loginResponse = new LoginResponse();
          loginResponse.setUser(user);
          loginResponse.setJwt(jwt);
          
          return ResultUtils.success(loginResponse);
      }
      

      測試結果:

      {
          "code": 0,
          "data": {
              "user": {
                  "id": 4,
                  "userAccount": "Lantz",
                  "userName": "lan",
                  "userAvatar": "https://pic.code-nav.cn/user_avatar/1872161376428277761/thumbnail/D5QaPIaHNcft2xW1.jpg",
                  "gender": 1,
                  "userPassword": "dd8fa48dc3e51a450c6141f5c0ad6665",
                  "phone": "12335555",
                  "email": "22334466@email.com",
                  "userStatus": 0,
                  "createTime": "2025-04-18T10:43:38.000+00:00",
                  "updateTime": null,
                  "isDelete": null,
                  "userRole": 1
              },
              "jwt": "eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyQWNjb3VudCI6IkxhbnR6IiwiaWQiOjQsInVzZXJOYW1lIjoibGFuIiwiZXhwIjoxNzYwMjczMzMxfQ.eWcD38s2pfmYin78IssVy2tqeq0SA5CWtAjbq5CKto0"
          },
          "message": "ok"
      }
      
      posted @ 2025-10-12 20:02  Lantz12  閱讀(17)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 国产99青青成人A在线| 色视频不卡一区二区三区| 熟妇人妻系列aⅴ无码专区友真希| 日韩中文日韩中文字幕亚| 66亚洲一卡2卡新区成片发布| 亚洲av区一区二区三区| 亚洲高清成人av在线| 大香伊蕉在人线国产最新2005| 日韩中文字幕综合第二页| 国产av一区二区午夜福利| 久久亚洲精品人成综合网| 又黄又爽又色的免费网站| 日韩中文字幕在线不卡一区| 亚洲精品一区二区口爆| 日韩人妻无码一区二区三区99| 天堂www在线中文| 国产精一品亚洲二区在线播放| 色一情一乱一区二区三区码| 亚洲五月天综合| 国产av一区二区三区久久| 亚洲乱理伦片在线观看中字| 国产精品一区二区中文| 亚洲一区二区三区丝袜| 国产成人 综合 亚洲欧洲| 四虎永久精品在线视频| 亚洲中文字幕无码永久在线| 国产台湾黄色av一区二区| 亚洲男人第一无码av网站| 久久综合九色综合欧洲98| 国产欧美一区二区精品性色| 粉嫩小泬无遮挡久久久久久| 中文字幕va一区二区三区| 同江市| 久久99热只有频精品8| 成人精品区| 亚洲中文字幕无码专区| 国产免费播放一区二区三区| 天天躁久久躁日日躁| 最新国产精品好看的精品| 国产精品污双胞胎在线观看| 大香伊蕉在人线国产免费|