前言
JWT(Json Web Token)是實現(xiàn)token技術(shù)的一種解決方案兽间,用于前端和服務(wù)端進行身份認(rèn)證鳖眼,本文只是基于如何快速創(chuàng)建秘鑰和解析秘鑰再悼,至于后端使用過濾器校驗邏輯,可自行補充
1. pom.xml
<dependencies>
<!-- web依賴 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- lombok依賴 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.8</version>
</dependency>
<!-- json工具 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.68</version>
</dependency>
<!-- jwt -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.0</version>
</dependency>
</dependencies>
2. JwtUtils
package com.lss.jwt_test.util;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import com.lss.jwt_test.rest.TestController;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.apache.tomcat.util.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class JwtUtils {
/**
* token 過期時間, 單位: 秒. 這個值表示 30 天
*/
private static final long TOKEN_EXPIRED_TIME = 30 * 24 * 60 * 60;
public static final String jwtId = "tokenId";
/**
* jwt 加密解密密鑰(可自行填寫)
*/
private static final String JWT_SECRET = "1234567890";
/**
* 創(chuàng)建JWT
*/
public static String createJWT(Map<String, Object> claims, Long time) {
SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256; //指定簽名的時候使用的簽名算法屡立,也就是header那部分褂痰,jjwt已經(jīng)將這部分內(nèi)容封裝好了亩进。
Date now = new Date(System.currentTimeMillis());
SecretKey secretKey = generalKey();
long nowMillis = System.currentTimeMillis();//生成JWT的時間
//下面就是在為payload添加各種標(biāo)準(zhǔn)聲明和私有聲明了
JwtBuilder builder = Jwts.builder() //這里其實就是new一個JwtBuilder,設(shè)置jwt的body
.setClaims(claims) //如果有私有聲明缩歪,一定要先設(shè)置這個自己創(chuàng)建的私有的聲明归薛,這個是給builder的claim賦值,一旦寫在標(biāo)準(zhǔn)的聲明賦值之后,就是覆蓋了那些標(biāo)準(zhǔn)的聲明的
.setId(jwtId) //設(shè)置jti(JWT ID):是JWT的唯一標(biāo)識主籍,根據(jù)業(yè)務(wù)需要习贫,這個可以設(shè)置為一個不重復(fù)的值,主要用來作為一次性token,從而回避重放攻擊崇猫。
.setIssuedAt(now) //iat: jwt的簽發(fā)時間
.signWith(signatureAlgorithm, secretKey);//設(shè)置簽名使用的簽名算法和簽名使用的秘鑰
if (time >= 0) {
long expMillis = nowMillis + time;
Date exp = new Date(expMillis);
builder.setExpiration(exp); //設(shè)置過期時間
}
return builder.compact();
}
/**
* 驗證jwt
*/
public static Claims verifyJwt(String token) {
//簽名秘鑰沈条,和生成的簽名的秘鑰一模一樣
SecretKey key = generalKey();
Claims claims;
try {
claims = Jwts.parser() //得到DefaultJwtParser
.setSigningKey(key) //設(shè)置簽名的秘鑰
.parseClaimsJws(token).getBody();
} catch (Exception e) {
claims = null;
}//設(shè)置需要解析的jwt
return claims;
}
/**
* 由字符串生成加密key
*
* @return
*/
public static SecretKey generalKey() {
String stringKey = JWT_SECRET;
byte[] encodedKey = Base64.decodeBase64(stringKey);
SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
return key;
}
/**
* 根據(jù)userId和openid生成token
*/
public static String generateToken(String openId, Integer userId) {
Map<String, Object> map = new HashMap<>();
map.put("userId", userId);
map.put("openId", openId);
map.put("sub", openId);
return createJWT(map, TOKEN_EXPIRED_TIME);
}
public static void main(String[] args) {
// 生成token
String s = generateToken("111", 20);
System.out.println(s);
// 驗證
String token = "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMTEiLCJvcGVuSWQiOiIxMTEiLCJleHAiOjE1OTI1NTc3ODMsInVzZXJJZCI6MjAsImlhdCI6MTU5MjU1NTE5MSwianRpIjoidG9rZW5JZCJ9.X7JHnx3Y5wtb-n3pT9tft2I4hENJdeRxW2QWaI4jv2E";
Claims claims = verifyJwt(token);
String subject = claims.getSubject();
String userId = (String)claims.get("userId");
String openId = (String)claims.get("openId");
String sub = (String)claims.get("sub");
System.out.println("subject:" + subject);
System.out.println("userId:" + userId);
System.out.println("openId:" + openId);
System.out.println("sub:" + sub);
}
}
3. 驗證
使用時可再main方法中驗證