JWT介绍
JWT(Java Web Token) 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准(RFC 7519)。JWT一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该Token也可直接被用于认证,也可被加密。
JWT能做什么?
- Authorization (授权) : 这是使用JWT的最常见场景。一旦用户登录,后续每个请求都将包含JWT,允许用户访问该令牌允许的路由、服务和资源。单点登录是现在广泛使用的JWT的一个特性,因为它的开销很小,并且可以轻松地跨域使用。
- Information Exchange (信息交换) : 对于安全的在各方之间传输信息而言,JSON Web Tokens无疑是一种很好的方式。因为JWT可以被签名,例如,用公钥/私钥对,你可以确定发送人就是它们所说的那个人。另外,由于签名是使用头和有效负载计算的,您还可以验证内容没有被篡改。
优势
-
基于JWT的认证方式,由于Json的通用性,所以JWT是可以进行跨语言支持。
-
JWT构成十分简洁,数据量小,传输速度很快。
-
载荷Payload中包含了所有用户需要的信息,可以避免多次查询数据库。
-
基于JWT的认证方式不需要在服务器端保存会话信息,特别适用于分布式微服务。
结构
一个jwt包含3个部分:头部header,载荷payload,签名signature。
头部header用于声明token类型和加密算法,payload载荷用于传递信息的载体,常用的有iss(签发者)、iat(签发时间)、exp(过期时间)、sub(面向的用户)、aud(接收方)等;签名signature用于将头部header和载荷payload编码后的字符串拼接后再用签名算法加密,加密过程中再加上密钥最终得到签名。
Header
头部通常由两部分组成:令牌类型(即JWT)和所使用的签名算法,例如HMAC SHA256或RSA。使用Base64编码
{
"alg":"HS256",
"typ":"JWT"
}
Payload
有效负载,其中包含声明,声明是有关实体(例如用户)和其他数据的声明。同样也是由Base64编码组成
{
"sub":"123456",
"name":"John",
"admin":true
}
Signature
前面两个部分是由Base64编码的,前端可以通过解码拿到里面的信息。Signature需要使用编码后的header和payload以及密钥,使用Header中指定的签名算法进行签名。签名的作用是保证JWT没有被篡改过。
HMACSHA256(base64UrlEncode(header) + "."+ base64UrlEncode(payload).secret);
安全问题
Base64是一种编码,是可逆的,我们的信息不就暴露了吗?
是的,所以在JWT中,不应该在负载里面加入任何敏感数据,例如用户密码。
JWT的第一个程序
引入依赖
<!-- 引入jwt-->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.12.0</version>
</dependency>
生成token
HashMap<String,Object> map = new HashMap();
Calendar instance = Calendar.getInstance();
instance.add(Calendar.SECOND,20);
String token = JWT.create().withHeader(map)//header
.withClaim("UserId",21)//payload
.withClaim("UserName","csy")
.withExpiresAt(instance.getTime())//指定令牌过期时间
.sign(Algorithm.HMAC256("DFSHJSUI"));//签名
System.out.println(token);
根据令牌和签名解析数据
//验签
//创建验证对象
JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256("DFSHJSUI")).build();
DecodedJWT decodedJWT = jwtVerifier.verify(token);
System.out.println(decodedJWT.getClaim("UserId").asInt());
封装工具类
public class JWTUtils {
private static final String SIGNATURE = "YUVUSY&*#&("; // 签名
/*
生成token
* */
public static String getToken(Map<String,String> map){
Calendar instance = Calendar.getInstance();
instance.add(Calendar.DATE,7); //默认7天过期
//创建jwt builder
JWTCreator.Builder builder = JWT.create();
//payload
map.forEach(builder::withClaim);
String token = builder.withExpiresAt(instance.getTime()).sign(Algorithm.HMAC256(SIGNATURE));
return token;
}
/*
验证token合法性
* */
public static void verify(String token){
JWT.require(Algorithm.HMAC256(SIGNATURE)).build().verify(token);
}
/*
获取token信息
* */
public static DecodedJWT getTokenInfo(String token){
DecodedJWT verify = JWT.require(Algorithm.HMAC256(SIGNATURE)).build().verify(token);
return verify;
}
}