<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          深入總結SpringBoot整合JWT,這應該是全網講的最通俗易懂的了

          共 7450字,需瀏覽 15分鐘

           ·

          2022-01-13 16:36

          JWT

          JWT(JSON Web Token)是為了在網絡應用環(huán)境間傳遞聲明而執(zhí)行的一種基于JSON的開放標準。

          舉例登錄過程

          在這里個人整理了一些資料,有需要的朋友可以直接點擊領取。

          Java基礎知識大全

          22本Java架構師核心書籍

          從0到1Java學習路線和資料

          1000+道2021年最新面試題

          組成

          JWT具體長什么樣呢?JWT是由三段信息構成的,將這三段信息文本用.鏈接一起就構成了JWT字符串。就像這樣:

          eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

          復制代碼

          元素

          header

          JWT的頭部承載兩部分信息:

          • 聲明類型,這里是JWT;

          • 聲明加密的算法,通常直接使用 HMAC SHA256;

          • 完整的頭部就像下面這樣的JSON:

          {
          'typ': 'JWT',
          'alg': 'HS256'
          }

          復制代碼

          使用base64加密,構成了第一部分。

          eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9

          復制代碼

          playload(重點)

          載荷就是存放有效信息的地方,這些有效信息包含三個部分:

          • 標準中注冊的聲明;

          • 公共的聲明;

          • 私有的聲明;

          其中,標準中注冊的聲明 (建議但不強制使用)包括如下幾個部分 :

          • iss: jwt簽發(fā)者;

          • sub: jwt所面向的用戶;

          • aud: 接收jwt的一方;

          • exp: jwt的過期時間,這個過期時間必須要大于簽發(fā)時間;

          • nbf: 定義在什么時間之前,該jwt都是不可用的;

          • iat: jwt的簽發(fā)時間;

          • jwt的唯一身份標識,主要用來作為一次性token,從而回避重放攻擊;

          公共的聲明部分:公共的聲明可以添加任何的信息,一般添加用戶的相關信息或其他業(yè)務需要的必要信息,但不建議添加敏感信息,因為該部分在客戶端可解密。

          私有的聲明部分:私有聲明是提供者和消費者所共同定義的聲明,一般不建議存放敏感信息,因為base64是對稱解密的,意味著該部分信息可以歸類為明文信息。

          定義一個payload:

          {
          "sub": "1234567890",
          "name": "John Doe",
          "admin": true
          }

          復制代碼

          然后將其進行base64加密,得到Jwt的第二部分:

          eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9

          復制代碼

          signature

          jwt的第三部分是一個簽證信息,這個簽證信息由三部分組成:

          var encodedString = base64UrlEncode(header) + '.' + base64UrlEncode(payload);


          var signature = HMACSHA256(encodedString, '密鑰');
          加密之后,得到signature簽名信息。

          TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

          復制代碼

          jwt最終格式

          eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
          復制代碼

          secret用來進行jwt的簽發(fā)和jwt的驗證,所以,在任何場景都不應該流露出去。

          元素

          SpringBoot整合JWT【正片】

          引入依賴




          com.auth0
          java-jwt


          復制代碼

          創(chuàng)建JWT工具類

          注意靜態(tài)屬性的配置文件注入方式:

          package com.neuq.common.util;

          import com.auth0.jwt.JWT;
          import com.auth0.jwt.algorithms.Algorithm;
          import com.auth0.jwt.exceptions.TokenExpiredException;
          import com.neuq.common.exception.ApiException;
          import com.neuq.common.response.ResultInfo;
          import org.springframework.boot.context.properties.ConfigurationProperties;
          import org.springframework.stereotype.Component;

          import java.util.Date;

          /**
          * @Author: xiang
          * @Date: 2021/5/11 21:11
          *


          * JwtToken生成的工具類
          * JWT token的格式:header.payload.signature
          * header的格式(算法、token的類型),默認:{"alg": "HS512","typ": "JWT"}
          * payload的格式 設置:(用戶信息、創(chuàng)建時間、生成時間)
          * signature的生成算法:
          * HMACSHA512(base64UrlEncode(header) + "." +base64UrlEncode(payload),secret)
          */

          @Component
          @ConfigurationProperties(prefix = "jwt")
          public class JWTUtils {

          //定義token返回頭部
          public static String header;

          //token前綴
          public static String tokenPrefix;

          //簽名密鑰
          public static String secret;

          //有效期
          public static long expireTime;

          //存進客戶端的token的key名
          public static final String USER_LOGIN_TOKEN = "USER_LOGIN_TOKEN";

          public void setHeader(String header) {
          JWTUtils.header = header;
          }

          public void setTokenPrefix(String tokenPrefix) {
          JWTUtils.tokenPrefix = tokenPrefix;
          }

          public void setSecret(String secret) {
          JWTUtils.secret = secret;
          }

          public void setExpireTime(int expireTimeInt) {
          JWTUtils.expireTime = expireTimeInt*1000L*60;
          }

          /**
          * 創(chuàng)建TOKEN
          * @param sub
          * @return
          */
          public static String createToken(String sub){
          return tokenPrefix + JWT.create()
          .withSubject(sub)
          .withExpiresAt(new Date(System.currentTimeMillis() + expireTime))
          .sign(Algorithm.HMAC512(secret));
          }


          /**
          * 驗證token
          * @param token
          */
          public static String validateToken(String token){
          try {
          return JWT.require(Algorithm.HMAC512(secret))
          .build()
          .verify(token.replace(tokenPrefix, ""))
          .getSubject();
          } catch (TokenExpiredException e){
          throw new ApiException(ResultInfo.unauthorized("token已經過期"));
          } catch (Exception e){
          throw new ApiException(ResultInfo.unauthorized("token驗證失敗"));
          }
          }

          /**
          * 檢查token是否需要更新
          * @param token
          * @return
          */
          public static boolean isNeedUpdate(String token){
          //獲取token過期時間
          Date expiresAt = null;
          try {
          expiresAt = JWT.require(Algorithm.HMAC512(secret))
          .build()
          .verify(token.replace(tokenPrefix, ""))
          .getExpiresAt();
          } catch (TokenExpiredException e){
          return true;
          } catch (Exception e){
          throw new ApiException(ResultInfo.unauthorized("token驗證失敗"));
          }
          //如果剩余過期時間少于過期時常的一般時 需要更新
          return (expiresAt.getTime()-System.currentTimeMillis()) < (expireTime>>1);
          }
          }


          復制代碼

          yaml屬性配置

          jwt:
          header: "Authorization" #token返回頭部
          tokenPrefix: "Bearer " #token前綴
          secret: "qwertyuiop7418520" #密鑰
          expireTime: 1 #token有效時間 (分鐘) 建議一小時以上
          復制代碼

          登錄方法將用戶信息存入token中返回

            @Override
          public Map login(User user) {
          //phone是除id外的唯一標志 需要進行檢查
          if (user.getPhone() == null || user.getPhone().equals(""))
          throw new ApiException("手機號不合法");
          User selectUser = userDao.selectUserByPhone(user.getPhone());
          if (selectUser == null) {
          //注冊用戶
          int count = userDao.insertUser(user);
          if (count < 1) throw new ApiException(ResultInfo.serviceUnavailable("注冊異常"));
          }
          //將userId存入token中
          String token = JWTUtils.createToken(selectUser.getUserId().toString());
          Map map = new HashMap<>();
          map.put("user",selectUser);
          map.put("token",token);
          return map;
          }

          復制代碼

          注意將token保存到Http 的 header

              @GetMapping("/login")
          public ResultInfo login(User user, HttpServletResponse response) {
          Map map = userService.login(user);
          //將token存入Http的header中
          response.setHeader(JWTUtils.USER_LOGIN_TOKEN, (String) map.get("token"));
          return ResultInfo.success((User)map.get("user"));
          }

          復制代碼

          攔截器驗證每次請求的token

          /**
          * @Author: xiang
          * @Date: 2021/5/7 20:56
          *


          * 攔截器:驗證用戶是否登錄
          */
          public class UserLoginInterceptor implements HandlerInterceptor {
          @Override
          public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
          //http的header中獲得token
          String token = request.getHeader(JWTUtils.USER_LOGIN_TOKEN);
          //token不存在
          if (token == null || token.equals("")) throw new ApiException("請先登錄");
          //驗證token
          String sub = JWTUtils.validateToken(token);
          if (sub == null || sub.equals(""))
          throw new ApiException(ResultInfo.unauthorized("token驗證失敗"));
          //更新token有效時間 (如果需要更新其實就是產生一個新的token)
          if (JWTUtils.isNeedUpdate(token)){
          String newToken = JWTUtils.createToken(sub);
          response.setHeader(JWTUtils.USER_LOGIN_TOKEN,newToken);
          }
          return true;
          }
          }

          復制代碼

          @Configuration
          @ComponentScan(basePackages = "com.neuq.common") //全局異常處理類需要被掃描才能
          public class WebMvcConfig implements WebMvcConfigurer {
          /**
          * 注冊自定義攔截器
          *
          * @param registry
          */
          @Override
          public void addInterceptors(InterceptorRegistry registry) {
          registry.addInterceptor(new UserLoginInterceptor())
          .addPathPatterns("/user/**")
          .addPathPatterns("/userInfo/**")
          .excludePathPatterns("/user/login");//開放登錄路徑
          }

          }

          復制代碼

          單點登錄

          將token或者一個唯一標識UUID=UUID.randomUUID().toString()存進Cookie中(別存在Http的header中了),設置路徑為整個項目根路徑/*;往往以這個唯一標識為key,用戶信息為value緩存在服務器中?。?!

          最后

          感謝大佬能看到最后,覺得文章對你有幫助記得點個贊!


          作者:程序員偉杰
          鏈接:https://juejin.cn/post/6962142423879270437
          來源:稀土掘金
          著作權歸作者所有。商業(yè)轉載請聯(lián)系作者獲得授權,非商業(yè)轉載請注明出處。



          瀏覽 53
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  免费一级aa| 夜色福利在线看 | 国产东北女人在线视频 | 无码中文字幕 | 中文字幕乱码中文乱码91 |