JWT介紹
-
JWT是JSON Web Token的縮寫,即JSON Web令牌,是一種自包含令牌, 是為了在網路應用環境間傳遞宣告而執行的一種基于JSON的開放標準,
-
JWT的宣告一般被用來在身份提供者和服務提供者間傳遞被認證的用戶身份資訊,以便于從資源服務器獲取資源,比如用在用戶登錄上,
-
JWT最重要的作用就是對 token資訊的防偽作用,
-
一個JWT由三個部分組成:JWT頭、有效載荷、簽名哈希
-
最后由這三者組合進行base64url編碼得到JWT
-
典型的,一個JWT看起來如下圖:該物件為一個很長的字串,字符之間通過"."分隔符分為三個子串,
https://jwt.io/
JWT頭
JWT頭部分是一個描述JWT元資料的JSON物件,通常如下所示,
{
"alg": "HS256",
"typ": "JWT"
}
在上面的代碼中,alg屬性表示簽名使用的演算法,默認為HMAC SHA256(寫為HS256);
typ屬性表示令牌的型別,JWT令牌統一寫為JWT,
最后,使用Base64 URL演算法將上述JSON物件轉換為字串保存,
有效載荷
有效載荷部分,是JWT的主體內容部分,也是一個JSON物件,包含需要傳遞的資料, JWT指定七個默認欄位供選擇,
iss: jwt簽發者
sub: 主題
aud: 接收jwt的一方
exp: jwt的過期時間,這個過期時間必須要大于簽發時間
nbf: 定義在什么時間之前,該jwt都是不可用的.
iat: jwt的簽發時間
jti: jwt的唯一身份標識,主要用來作為一次性token,從而回避重放攻擊,
{
"name": "Helen",
"role": "editor",
"avatar": "helen.jpg"
}
請注意,默認情況下JWT是未加密的,任何人都可以解讀其內容,因此不要構建隱私資訊欄位,存放保密資訊,以防止資訊泄露,
JSON物件也使用Base64 URL演算法轉換為字串保存,
簽名哈希
簽名哈希部分是對上面兩部分資料簽名,通過指定的演算法生成哈希,以確保資料不會被篡改,
首先,需要指定一個密碼(secret),該密碼僅僅為保存在服務器中,并且不能向用戶公開,然后,使用標頭中指定的簽名演算法(默認情況下為HMAC SHA256)根據以下公式生成簽名,
HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(claims), secret) ==> 簽名hash
在計算出簽名哈希后,JWT頭,有效載荷和簽名哈希的三個部分組合成一個字串,每個部分用"."分隔,就構成整個JWT物件,
Base64URL演算法
如前所述,JWT頭和有效載荷序列化的演算法都用到了Base64URL,該演算法和常見Base64演算法類似,稍有差別,
作為令牌的JWT可以放在URL中(例如api.example/?token=xxx), Base64中用的三個字符是"+","/"和"=",由于在URL中有特殊含義,因此Base64URL中對他們做了替換:"="去掉,"+"用"-"替換,"/"用"_"替換,這就是Base64URL演算法,
Spring Boot中集成JWT
- 匯入jwt的pom依賴
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
</dependency>
- 添加JWT幫助類
import io.jsonwebtoken.*;
import org.springframework.util.StringUtils;
import java.util.Date;
public class JwtHelper {
private static long tokenExpiration = 365 * 24 * 60 * 60 * 1000;
private static String tokenSignKey = "123456";
public static String createToken(Long userId, String username) {
String token = Jwts.builder()
.setSubject("AUTH-USER")
.setExpiration(new Date(System.currentTimeMillis() + tokenExpiration))
.claim("userId", userId)
.claim("username", username)
.signWith(SignatureAlgorithm.HS512, tokenSignKey)
.compressWith(CompressionCodecs.GZIP)
.compact();
return token;
}
public static Long getUserId(String token) {
try {
if (StringUtils.isEmpty(token)) return null;
Jws<Claims> claimsJws = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token);
Claims claims = claimsJws.getBody();
Integer userId = (Integer) claims.get("userId");
return userId.longValue();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static String getUsername(String token) {
try {
if (StringUtils.isEmpty(token)) return "";
Jws<Claims> claimsJws = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token);
Claims claims = claimsJws.getBody();
return (String) claims.get("username");
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static void main(String[] args) {
String token = JwtHelper.createToken(1L, "admin");
System.out.println(token);
System.out.println(JwtHelper.getUserId(token));
System.out.println(JwtHelper.getUsername(token));
}
}
- Controller的使用
@Autowired
private SysUserService sysUserService;
@ApiOperation(value = "https://www.cnblogs.com/FkClass/archive/2023/05/18/登錄")
@PostMapping("login")
public Result login(@RequestBody LoginVo loginVo) {
SysUser sysUser = sysUserService.getByUsername(loginVo.getUsername());
if(null == sysUser) {
throw new GuiguException(201,"用戶不存在");
}
if(!MD5.encrypt(loginVo.getPassword()).equals(loginVo.getPassword())) {
throw new GuiguException(201,"密碼錯誤");
}
if(sysUser.getStatus().intValue() == 0) {
throw new GuiguException(201,"用戶被禁用");
}
Map<String, Object> map = new HashMap<>();
map.put("token", JwtHelper.createToken(sysUser.getId(), sysUser.getUsername()));
return Result.ok(map);
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/552823.html
標籤:其他
上一篇:java常用類
下一篇:返回列表