JWT安全驗證常見疑問解答

最近做基於BFF架構的分佈式移動端API接口的系統設計。工作過程中發現有些工程師對JWT安全驗證的認識存在一些偏差,重複講解實在太麻煩了,在這裏把關於JWT常見的一些疑問統一回答下吧。

  1. 什麼是JWT?

JSON Web Token (JWT)是一種基於 token 的認證方案。
JSON Web Tokens are an open, industry standard RFC 7519 method for representing claims securely between two parties.
簡單的說,JWT就是一種Token的編碼算法,服務器端負責根據一個密碼和算法生成Token,然後發給客戶端,客戶端只負責後面每次請求都在HTTP header裏面帶上這個Token,服務器負責驗證這個Token是不是合法的,有沒有過期等,並可以解析出subject和claim裏面的數據。

注意JWT裏面的數據是BASE64編碼的,沒有加密,因此不要放如敏感數據。

可以通過https://jwt.io/這個網站對JWT Token進行解析。

一個JWT token 看起來是這樣的:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjEzODY4OTkxMzEsImlzcyI6ImppcmE6MTU0ODk1OTUiLCJxc2giOiI4MDYzZmY0Y2ExZTQxZGY3YmM5MGM4YWI2ZDBmNjIwN2Q0OTFjZjZkYWQ3YzY2ZWE3OTdiNDYxNGI3MTkyMmU5IiwiaWF0IjoxMzg2ODk4OTUxfQ.uKqU9dTB6gKwG6jQCuXYAiMNdfNRw98Hw_IWuA5MaMo

可以簡化爲下面這樣的結構:

base64url_encode(Header) + '.' + base64url_encode(Claims) + '.' + base64url_encode(Signature)
  1. 爲什麼用JWT?

JWT只通過算法實現對Token合法性的驗證,不依賴數據庫,Memcached的等存儲系統,因此可以做到跨服務器驗證,只要密鑰和算法相同,不同服務器程序生成的Token可以互相驗證。

  1. JWT Token需要持久化在Memcached中嗎?
    不應該這樣做,這樣就背離了JWT通過算法驗證的初心。

  2. 在退出登錄時怎樣實現JWT Token失效呢?
    退出登錄, 只要客戶端端把Token丟棄就可以了,服務器端不需要廢棄Token。

  3. 怎樣保持客戶端長時間保持登錄狀態?

服務器端提供刷新Token的接口, 客戶端負責按一定的邏輯刷新服務器Token。

  1. 服務器端是否應該從JWT中取出userid用於業務查詢?

REST API是無狀態的,意味着服務器端每次請求都是獨立的,即不依賴以前請求的結果,因此也不應該依賴JWT token做業務查詢, 應該在請求報文中單獨加個userid 字段。
爲了做用戶水平越權的檢查,可以在業務層判斷傳入的userid和從JWT token中解析出的userid是否一致, 有些業務可能會允許查不同用戶的數據。

  1. JWT 在Java項目中如何實現?

生成Token


      String token = Jwts.builder().setSubject(userId)
              .setExpiration(new Date(System.currentTimeMillis() + Constant.TOKEN_EXP_TIME))
              .claim("roles", Constant.USER_TYPE_EMP).setIssuedAt(new Date())
              .signWith(SignatureAlgorithm.HS256, Constant.JWT_SECRET).compact();
      loginResponse.setToken(token);

驗證JWT Token


      final String authHeader = request.getHeader("Authorization");

     if (authHeader == null || !authHeader.startsWith("Bearer ")) {
        log.debug("no Authorization ", e);
         return;
     } else {
         try {
             final String token = authHeader.substring(7); // The part after "Bearer "
             log.debug("token " + token);

             final Claims claims = Jwts.parser().setSigningKey(Constant.JWT_SECRET)
                     .parseClaimsJws(token).getBody();
             log.debug(claims.toString());
         } catch (Exception e) { //包含超時,簽名錯誤等異常

             log.debug("JWT Exception", e);
             return;
         }
     }

注意客戶端發送的Authorization HTTP HEADER格式是 "Bearer YOUR_JWT_TOKEN",這是OAuth的規範規定的。



作者:offbye西濤
鏈接:https://www.jianshu.com/p/b952c08aed09
來源:簡書
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章