一、工具類代碼
/* * 總的來說,工具類中有三個方法 * 獲取JwtToken,獲取JwtToken中封裝的信息,判斷JwtToken是否存在 * 1. encode(),參數是=簽發人,存在時間,一些其他的信息=。返回值是JwtToken對應的字符串 * 2. decode(),參數是=JwtToken=。返回值是荷載部分的鍵值對 * 3. isVerify(),參數是=JwtToken=。返回值是這個JwtToken是否存在 * */ public class JwtUtil { // 創建默認的秘鑰和算法,供無參的構造方法使用 private static final String defaultbase64EncodedSecretKey = "xxx"; private static final SignatureAlgorithm defaultsignatureAlgorithm = SignatureAlgorithm.HS256; public JwtUtil() { this(defaultbase64EncodedSecretKey, defaultsignatureAlgorithm); // 調用本類的構造方法 } private final String base64EncodedSecretKey; private final SignatureAlgorithm signatureAlgorithm; public JwtUtil(String secretKey, SignatureAlgorithm signatureAlgorithm) { this.base64EncodedSecretKey = Base64.encodeBase64String(secretKey.getBytes()); // 這樣給成員變量賦值是為了讓成員方法也能使用 this.signatureAlgorithm = signatureAlgorithm; } /* * 這里就是產生jwt字符串的地方 jwt字符串包括三個部分 1. header -當前字符串的類型,一般都是“JWT” * -哪種算法加密,“HS256”或者其他的加密算法 所以一般都是固定的,沒有什么變化 2. payload 一般有四個最常見的標准字段(下面有) * iat:簽發時間,也就是這個jwt什么時候生成的 jti:JWT的唯一標識 iss:簽發人,一般都是username或者userId exp:過期時間 * */ public String encode(String iss, long ttlMillis, Map<String, Object> claims) { // iss簽發人,ttlMillis生存時間,claims是指還想要在jwt中存儲的一些非隱私信息 if (claims == null) { claims = new HashMap<>(); } long nowMillis = System.currentTimeMillis(); JwtBuilder builder = Jwts.builder().setClaims(claims).setId(UUID.randomUUID().toString())// 2. // 這個是JWT的唯一標識,一般設置成唯一的,這個方法可以生成唯一標識 .setIssuedAt(new Date(nowMillis))// 1. 這個地方就是以毫秒為單位,換算當前系統時間生成的iat .setSubject(iss)// 3. 簽發人,也就是JWT是給誰的(邏輯上一般都是username或者userId) .signWith(signatureAlgorithm, base64EncodedSecretKey);// 這個地方是生成jwt使用的算法和秘鑰 if (ttlMillis >= 0) { long expMillis = nowMillis + ttlMillis; Date exp = new Date(expMillis);// 4. 過期時間,這個也是使用毫秒生成的,使用當前時間+前面傳入的持續時間生成 builder.setExpiration(exp); } return builder.compact(); } // 相當於encode的方向,傳入jwtToken生成對應的username和password等字段。Claim就是一個map // 也就是拿到荷載部分所有的鍵值對 public Claims decode(String jwtToken) { // 得到 DefaultJwtParser return Jwts.parser() // 設置簽名的秘鑰 .setSigningKey(base64EncodedSecretKey) // 使用成員變量的值 // 設置需要解析的 jwt .parseClaimsJws(jwtToken).getBody(); } // 判斷jwtToken是否合法 public boolean isVerify(String jwtToken) { // 這個是官方的校驗規則,這里只寫了一個”校驗算法“,可以自己加 Algorithm algorithm = null; switch (signatureAlgorithm) { case HS256: algorithm = Algorithm.HMAC256(Base64.decodeBase64(base64EncodedSecretKey)); break; default: throw new RuntimeException("不支持該算法"); } JWTVerifier verifier = JWT.require(algorithm).build(); verifier.verify(jwtToken); // 校驗不通過會拋出異常 // 判斷合法的標准:1. 頭部和荷載部分沒有篡改過。2. 沒有過期 return true; } public static void main(String[] args) { JwtUtil util = new JwtUtil("tom", SignatureAlgorithm.HS256); // 以tom作為秘鑰,以HS256加密 Map<String, Object> map = new HashMap<>(); map.put("username", "tom"); map.put("password", "123456"); map.put("age", 20); String jwtToken = util.encode("tom", 30000, map); System.out.println(jwtToken); util.decode(jwtToken).entrySet().forEach((entry) -> { System.out.println(entry.getKey() + ": " + entry.getValue()); }); } }
如果encode的第二個參數ttlMillis為負數,表示永遠不會過期。
二、工具類的使用
生成jwt
@PostMapping(value = "/applogin") public JSONObject loginAccount(@RequestBody JSONObject json) throws Exception { JSONObject result = new JSONObject(); String username = json.getString("username"); String password = json.getString("password"); // 獲取用戶信息 User user = userService.getUser(username, password); if (user != null) { user.setPassword(null); // 清除密碼,即密碼信息不返回給前端 result.put("userInfo", user); // 生成token JwtUtil jwtUtil = new JwtUtil(); Map<String, Object> chaim = new HashMap<>(); chaim.put("username", username); String jwtToken = jwtUtil.encode(username, -1, chaim); // 參數一為簽發人,第二個參數為過期時間,第三個參數為payload result.put("result", true); result.put("token", jwtToken); } else { result.put("result", false); result.put("msg", "用戶名或密碼錯誤"); } return result; }
從jwt中獲取username
public class BaseController { @Resource private IUserService userService; public User getSessionUser() { Subject subject = SecurityUtils.getSubject(); String jwtToken = (String) subject.getPrincipal(); JwtUtil jwtUtil = new JwtUtil(); Claims decode = jwtUtil.decode(jwtToken); String phone = decode.get("username", String.class); QueryWrapper<User> wrapper = new QueryWrapper<User>(); wrapper.eq("user_phone", phone).or().eq("user_no", phone); User user = userService.getOne(wrapper); return user; } }