JsonWebToken介绍
JsonWebToken(简称JWT)是实现token技术的一种解决方案,它包含三部分,分别是: 头部(header ),载荷(payload ),签名 (signature)。
他们按照 A.B.C
的格式拼接起来,其中C由A和B生成,他们之间的格式为 Base64(header).Base64(payload).H256(A.B)
(也可以使用不同的签名算法,默认情况下是HS256)。需要注意的是header和payload都是使用Base64URL
算法对象序列化之后的字符串.
名词解释:
HS256: HMACSHA256,一种消息摘要算法
Base64URL: Base64中用的三个字符是"+"
,"/"
和"="
,由于在URL中有特殊含义,因此Base64URL中对他们做了替换:"="
去掉,"+"
用"-"
替换,"/"
用"_"
替换,这就是Base64URL算法。
结构
头部(header)
Header 部分是一个 JSON 对象,描述 JWT 的元数据,一般很少改动直接使用默认的即可
{
"typ": "JWT",
"alg": "HS256"
}
alg
属性表示签名的算法(algorithm);typ
属性表示这个令牌(token)的类型(type),JWT 令牌统一写为JWT
。
载荷(playload)
Payload 部分也是一个 JSON 对象,用来存放实际需要传递的数据。
可自行指定字段,很灵活,也有固定字段表示特定含义(但不一定要包含特定字段,只是推荐)。下面是官方推荐的字段:
{
"iss": "签发者",
"sub": "当前令牌的描述说明",
"aud": "接收方",
"exp": "过期时间",
"iat": "创建时间",
"nbf": "在什么时间之前,该Token不可用",
"jti": "Token唯一标识"
}
下面就是一个例子:
{
"sub": "1234567890",
"name": "John Doe",
"admin": true
}
签名(signature)
Signature 部分是对前两部分的签名,防止数据篡改。
首先,需要指定一个密钥(secret)。这个密钥只有服务器才知道,不能泄露给用户。然后,使用 Header 里面指定的签名算法(默认是 HMAC SHA256),按照下面的公式产生签名。
HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload) , secret)
密钥在摘要算法中起盐值的作用。
算出签名以后,将header和payload用Base64URL算法对象序列化,然后把这三部分用“.”拼接起来就是生成的token了。
io.jsonwebtoken.jjwt工具使用
maven依赖:
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
下面是一个示例工具类:
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.util.StringUtils;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
/**
* @author
*/
public class JwtUtils {
//过期时间
public static final long EXPIRE = 1000 * 60 * 60 * 24;
//签名密钥
public static final String SECRET = "ukc8BDbRigUDaY6pZFfWus2jZWLPHO";
/**
* 使用用户id和nickname获取一个token字符串
*/
public static String getJwtToken(String id, String nickname){
//使用builder构造一个JwtToken
String JwtToken = Jwts.builder()
//头部信息
.setHeaderParam("typ", "JWT")
.setHeaderParam("alg", "HS256")
//载荷中的推荐信息
.setSubject("guli-user")
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + EXPIRE))
//载荷中的自定义信息
.claim("id", id)
.claim("nickname", nickname)
//签名
.signWith(SignatureAlgorithm.HS256, SECRET)
//Base64URL前两部分并连接签名,获取token
.compact();
return JwtToken;
}
/**
* 判断传入的token字符串是否存在与有效
*/
public static boolean checkToken(String jwtToken) {
if(StringUtils.isEmpty(jwtToken)) return false;
try {
//使用parser解析jwt信息
Jwts.parser().setSigningKey(SECRET).parseClaimsJws(jwtToken);
//如果格式不对,会抛出UnsupportedJwtException异常
//如果验证签名失败,会抛出SignatureException异常
//如果token过期,会抛出ExpiredJwtException异常
//如果字符串为空,会抛出IllegalArgumentException异常
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
/**
* 判断HttpServletRequest中头部携带的token是否存在与有效
*/
public static boolean checkToken(HttpServletRequest request) {
try {
String jwtToken = request.getHeader("token");
if(StringUtils.isEmpty(jwtToken)) return false;
Jwts.parser().setSigningKey(SECRET).parseClaimsJws(jwtToken);
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
/**
* 根据token获取用户id
* @param request
* @return
*/
public static String getMemberIdByJwtToken(HttpServletRequest request) {
String jwtToken = request.getHeader("token");
if(StringUtils.isEmpty(jwtToken)) return "";
Jws<Claims> claimsJws = Jwts.parser().setSigningKey(SECRET).parseClaimsJws(jwtToken);
//getBody获取用户在载荷中定义的信息
Claims claims = claimsJws.getBody();
return (String)claims.get("id");
}
}
原创文章,作者:彭晨涛,如若转载,请注明出处:https://www.codetool.top/article/jwt%e7%bb%93%e6%9e%84%e5%8f%8aio-jsonwebtoken-jjwt%e5%b7%a5%e5%85%b7%e4%bd%bf%e7%94%a8/