JWT實現登錄認證實例


JWT全稱JSON Web Token,是一個緊湊的,自包含的,安全的信息交換協議。JWT有很多方面的應用,例如權限認證,信息交換等。本文將簡單介紹JWT登錄權限認證的一個實例操作。

JWT組成

JWT由頭部(Header),負載(Payload)和簽名(Signature)三部分組成。其中頭部包含了JWT的聲明信息,例如簽名所用的算法等。

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

負載部分是負責信息的承載,在通信過程中,我們將要交換的信息放置於負載部分。

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

簽名部分是JWT安全的保障,在傳輸過程中,頭部和負載部分會經過Base64編碼在網絡中明文傳輸,既然是明文,為了保障信息在傳輸過程中不被篡改。JWT會對編碼之后的頭部和負載進行一個消息簽名。

Signature = HMACSHA256(header + "." + payload + secret)

經過簽名之后的JWT保證了數據不會被劫持並篡改。其中secret極為重要,即使有人劫持了消息,在不知道secret的情況下,無法簽名出一個有效的JWT。

JWT的形式

JWT由三部分組成:頭部,負載和簽名。最終的JWT字串可以呈現出這三部分,在JWT中,.為分割各部分的分隔符,按照順序依次為頭部,負載和簽名。不過這時你已經看不到JSON的形式,頭部和負載會經過Base64編碼,最終得到一個字符串。不過Base64並不是加密算法,它是一種編碼格式,你可以通過一定的工具解碼之后就會得到相應的JSON字串。

JWT的形式

JWT實現權限認證

在互聯網Web應用開發中,最為常見的一項工作就是認證用戶,狀態化HTTP請求和授予資源訪問權限。

其中認證用戶通過用戶名、密碼的登錄操作實現,但是HTTP請求是無狀態的,為了標記已經登錄成功的用戶,我們可以通過設置SESSION_IDCOOKIE來標記認證過的請求。但是它們都需要在服務端額外的存儲這些SESSION_IDCOOKIE。在最初的單體應用架構中,存儲可以在服務端中開辟一塊內存,以鍵值對的形式存儲SESSION_ID,COOKIE與用戶的映射關系。分布式架構中可以使用REDIS等中間件來實現SESSION共享。

為什要存儲映射關系?通過SESSION_IDCOOKIE我們不能夠直接得到用戶信息嗎?其實並不是不可以,而是不安全,SESSION_IDCOOKIE是可以供用戶自由操作的。如果直接明文形式的將用戶信息寫入其中,那么這些信息極有可能會被篡改。所以通常我們會在服務端生成隨機字串,寫入到SESSION_IDCOOKIE中,再將隨機字串與用戶之間建立一個映射。這樣,客戶端的用戶並不能隨意篡改這些信息了。因為並不知道其他用戶的隨機字串是什么。

JWT也是字串,只不過是編碼之后的字串,而且這個字串是安全的。因為它是被服務端簽名認證的。如果有用戶修改的痕跡,那么服務端在檢驗時會發現字串被修改。正是這一特性保障了認證的安全性。

在業務中,JWT可以實現雙向校驗,即通信雙方都可以校驗JWT有無被篡改。實現方式是通過非對稱加密技術。

Java-JWT權限認證Demo

登陸成功之后,服務端簽發JWT代碼:

final long expireTime = 1000 * 60 * 60 * 4; //JWT有效期為4小時
final String loginWebToken = JWT.create()
  .withIssuer(configurationProperties.getJwtLoginIssuer())
  .withClaim("username", vo.getUsername()) // 負載部分
  .withClaim("user_id", admin.getId())
  .withExpiresAt(new Date(System.currentTimeMillis() + expireTime)) // 設置有效期
  .sign(Algorithm.HMAC256(configurationProperties.getJwtSignKey())); // 進行簽名

簽發的JWT可以直接返回給客戶端,有客戶端JS代碼寫入下次請求的指定位置,也可以由服務端寫入SESSION_IDCOOKIE中。

校驗JWT代碼,攔截未認證的請求:

try
{
    final String loginWebToken = request.getHeader("Authorization");
    //            final DecodedJWT decodeToken = JWT.decode(loginWebToken);
    //            String username = decodeToken.getClaim("username").asString();
    // JWT驗證
    JWT.require(Algorithm.HMAC256(configurationProperties.getJwtSignKey()))
      .withIssuer(configurationProperties.getJwtLoginIssuer())
      .build().verify(loginWebToken);
    return true;
}catch (Exception ex)
{
    Response re = new Response()
      .setMsg("權限受限,請登陸")
      .setData(null)
      .setSuccess(false);
    response.reset();
    response.setCharacterEncoding("UTF-8");
    response.setContentType("application/json;charset=UTF-8");
    response.getWriter().print(JSON.toJSONString(re));
    return false;
}

業務中使用JWT實現HTTP狀態化,服務不同認證用戶:

@GetMapping("/user/info")
public Response getUserInfo(HttpServletRequest req)
{
  	final String loginWebToken = request.getHeader("Authorization");
  	final DecodedJWT jwt = JWT.decode(loginWebToken);
  	log.info("歡迎{}使用系統", jwt.getClaim("username");
  	return userService.getUserInfo(jwt.getClaim("user_id"));
}


免責聲明!

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



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