首頁 > Java > java教程 > Spring Boot怎麼整合JWT實現前後端認證

Spring Boot怎麼整合JWT實現前後端認證

WBOY
發布: 2023-05-18 13:19:06
轉載
1480 人瀏覽過

JWT簡介

JWT(全名:Json Web Token)是一個開放標準(RFC 7519),它定義了一種緊湊的、自包含的方式,用於作為JSON對像在各方之間安全地傳輸訊息。

為什麼要用JWT

傳統session認證有那些弊端?

  • 每個使用者的登入資訊都會儲存到伺服器的Session中,隨著使用者的增多,伺服器開銷會明顯增大。

  • Session的資訊存放在伺服器的記憶體中,對於分散式應用會導致失效,雖然可以將session的資訊統一存放在Redis的快取中,但這樣可能增加了複雜性。

  • 由於Session認證是基於Cookie實現,而針對非瀏覽器端和手機的行動端都不適用。

  • 前後端分離系統,由於前後端存在跨域,而Cookie資訊無法跨越,所以採用Session認證也是無法繼續寧跨域認證。

JWT認證的優勢

  • 簡潔:JWT Token資料量小,傳輸速度也很快。

  • 跨語言: JWT Token是以JSON加密形式保存在客戶端的,所以JWT是跨語言的,任何web形式都支援。跨平台:不依賴cookie和session,無需將session資訊存放在服務端,非常適合分散式應用,應用於擴充功能。

JWT的資料結構

Spring Boot怎麼整合JWT實現前後端認證

#Header

JWT第一部分是頭部分,它是一個描述JWT元資料的Json對象,通常如下所示。

{
    "alg": "HS256",
    "typ": "JWT"
}
登入後複製

alg屬性表示簽章使用的演算法,預設為HMAC SHA256(寫為HS256),typ屬性表示令牌的類型,JWT令牌統一寫為JWT。

Payload

JWT第二部分是Payload,也是一個Json對象,除了包含需要傳遞的數據,還有七個預設的欄位可供選擇。 iss:發行人exp:到期時間sub:主題aud:用戶nbf:在此之前不可用iat:發佈時間jti:JWT ID用於標識該JWT

{
    //默认字段
    "sub":"主题123",
    //自定义字段
    "name":"java",
    "isAdmin":"true",
    "loginTime":"2021-12-05 12:00:03"
}
登入後複製

需要注意的是,預設情況下JWT是未加密的,任何人都可以解讀其內容,因此如果一些敏感資訊不要存放在此,以防資訊洩露。 JSON物件也使用Base64 URL演算法轉換為字串保存。

Signature

簽名雜湊部分是對上面兩部分資料簽名,需要使用base64編碼後的header和payload數據,透過指定的演算法產生哈希,以確保資料不會被篡改。

Spring Boot整合JWT

引入Jwt套件

<dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt</artifactId>
        <version>0.9.1</version>
  </dependency>
登入後複製

寫jwt工具類別

public class JwtUtil
{
//创建jwt
public static String createJWT(String subject, String issue, Object claim,
            long ttlMillis)
    {
       //当前时间
        long nowMillis = System.currentTimeMillis();
        //过期时间
        long expireMillis = nowMillis + ttlMillis;
        String result = Jwts.builder()
                .setSubject(subject) //设置主题
                .setIssuer(issue) //发行者
                .setId(issue)//jwtID
                .setExpiration(new Date(expireMillis)) //设置过期日期
                .claim("user", claim)//主题,可以包含用户信息
                .signWith(getSignatureAlgorithm(), getSignedKey())//加密算法
                .compressWith(CompressionCodecs.DEFLATE).compact();//对载荷进行压缩

        return result;
    }
    
    // 解析jwt
    public static Jws<Claims> pareseJWT(String jwt)
    {
        Jws<Claims> claims;
        try
        {
            claims = Jwts.parser().setSigningKey(getSignedKey())
                    .parseClaimsJws(jwt);
        }
        catch (Exception ex)
        {
            claims = null;
        }
        return claims;
    }

   //获取主题信息
    public static Claims getClaims(String jwt)
    {
        Claims claims;
        try
        {
            claims = Jwts.parser().setSigningKey(getSignedKey())
                    .parseClaimsJws(jwt).getBody();
        }
        catch (Exception ex)
        {
            claims = null;
        }
        return claims;
    }
  }
  
   /**
     * 获取密钥
     * 
     * @return Key
     */
    private static Key getSignedKey()
    {
        byte[] apiKeySecretBytes = DatatypeConverter
                .parseBase64Binary(getAuthKey());
        Key signingKey = new SecretKeySpec(apiKeySecretBytes,
                getSignatureAlgorithm().getJcaName());
        return signingKey;
    }
    
    private static SignatureAlgorithm getSignatureAlgorithm()
    {
        return SignatureAlgorithm.HS256;
    }
  
  //获取密钥,可以动态配置
  public static String getAuthKey()
  {
        String auth = "123@#1234";
  }
登入後複製

Token認證攔截器

 Component
public class TokenInterceptor extends HandlerInterceptorAdapter
{
    public static Log logger = LogManager.getLogger(TokenInterceptor.class);

    @Override
    public boolean preHandle(HttpServletRequest request,
            HttpServletResponse response, Object handler) throws Exception
    {
        String uri = request.getRequestURI();
        logger.info("start TokenInterceptor preHandle.." + uri);
         
		//需要过滤特殊请求
        if (SystemUtil.isFree(uri) || SystemUtil.isProtected(uri))
        {
            return true;
        }
        
		
        String metohd=request.getMethod().toString();
        logger.info("TokenInterceptor request method:"+metohd);
        //options 方法需要过滤
        if("OPTIONS".equals(metohd))
        {
            return true;   
        }
        
		//是否开启token认证
        boolean flag = SystemUtil.getVerifyToken();
        ResponseResult result = new ResponseResult();
		//从请求的head信息中获取token
        String token = request.getHeader("X-Token");

        if (flag)
        {
            if(StringUtils.isEmpty(token))
            {
                token=request.getParameter("X-Token");    
            }
            // token不存在
            if (StringUtils.isEmpty(token))
            {
                result.setCode(ResultCode.NEED_AUTH.getCode());
                result.setMsg(ResultCode.NEED_AUTH.getMsg());
                WebUtil.writeJson(result, response);
                return false;
            }
            else
            {
                Claims claims = JwtUtil.getClaims(token);
                String subject = "";
                if (claims != null)
                {
                    subject = claims.getSubject();
                    // 验证主题
                    if (StringUtils.isEmpty(subject))
                    {
                        result.setCode(ResultCode.INVALID_TOKEN.getCode());
                        result.setMsg(ResultCode.INVALID_TOKEN.getMsg());
                        WebUtil.writeJson(result, response);
                        return false;
                    }								
                }
                else
                {
                    result.setCode(ResultCode.INVALID_TOKEN.getCode());
                    result.setMsg(ResultCode.INVALID_TOKEN.getMsg());
                    WebUtil.writeJson(result, response);
                    return false;
                }
            }
        }
        return true;
    }

}
登入後複製

設定攔截器

@Configuration
public class WebConfig implements WebMvcConfigurer
{
    @Resource
    private TokenInterceptor tokenInterceptor;

    public void addInterceptors(InterceptorRegistry registry)
    {
        registry.addInterceptor(tokenInterceptor).addPathPatterns("/**");
    }
 }
登入後複製

登入驗證流程

Spring Boot怎麼整合JWT實現前後端認證

範例程式碼

@RequestMapping("login")
public Result login(HttpServletResponse response)
{
    Map<String, Object> map = new HashMap<>();
    //
    Result result = loginAuth(user);
    int code = result.getCode();
            //登录认证成功
    if (code ==ResultCode.SUCCESS)
    {
        //默认为7天
        Long ttlMillis = 7*1000 * 60 * 60 * 24;
        //过期时间
        long expreTime = System.currentTimeMillis() + ttlMillis;
        String tokenKey = UUID.randomUUID().toString();
        String tokenId = JwtUtil.createJWT(user.getUserId(), tokenKey,
                user.getPassword(), expreTime);                   
        map.put("expreTime", expreTime);				
        map.put("tokenId", tokenId);           
    }
    else
    {
        logger.error("login error:" +FastJsonUtil.toJSONString(result));
    }
    return result;
}
登入後複製

以上是Spring Boot怎麼整合JWT實現前後端認證的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:yisu.com
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板