Java基础之《JWT使用》

一、JWT基础

1、Json web token (JWT) 的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源。也可以增加一些额外的其他业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。

2、jwt官网
https://jwt.io/

3、传统的token
传统的token,例如:用户登录成功生成对应的令牌,key为令牌,value为userid,隐藏了数据真实性,同时将该token存放到redis中,返回对应的真实令牌给客户端存放。
有状态的token会在服务端存一份,类似session id,通过和服务器保存的token比对后确认合法性。

4、为什么不再用session id
session缺点,集群无法共享。

这个类似于session id的token需要存在redis中。前端传token,后端通过token获取userid,再用userid进行操作。

所以token依赖于redis,获取真实token存放value值。

5、使用token缺点
每次都需要根据token查询真实内容。对服务器端的压力非常大。

二、jwt例子

1、pom文件添加依赖

<!--JWT支持-->
<dependency>
	<groupId>io.jsonwebtoken</groupId>
	<artifactId>jjwt-api</artifactId>
	<version>0.11.5</version>
</dependency>
<dependency>
	<groupId>io.jsonwebtoken</groupId>
	<artifactId>jjwt-impl</artifactId>
	<version>0.11.5</version>
</dependency>
<dependency>
	<groupId>io.jsonwebtoken</groupId>
	<artifactId>jjwt-jackson</artifactId>
	<version>0.11.5</version>
</dependency>

2、JWTDemo.java

package myboot;

import java.util.Date;

import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.jackson.io.JacksonSerializer;

public class JWTDemo {

	public static void main(String[] args) {
		//jwt秘钥
		String signKey = "test123test123test123test123test123test123test123";
		//创建jwt
		JwtBuilder jwtBuilder =Jwts.builder().setId("66").setSubject("test123")
				.setIssuedAt(new Date())
				.claim("username", "zhangsan123123")
				//设置签名值
				.signWith(SignatureAlgorithm.HS256, signKey)
				//添加序列化
				.serializeToJsonWith(new JacksonSerializer<>());
		System.out.println(jwtBuilder.compact());
	}
}

执行结果:

eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI2NiIsInN1YiI6InRlc3QxMjMiLCJpYXQiOjE2Njc4MDE3MDUsInVzZXJuYW1lIjoiemhhbmdzYW4xMjMxMjMifQ.3wkV3WrPyjxyUs-9E_4-1QcpExE2N14zxFP_MlgAtjQ

3、报错密钥最少要256位
Exception in thread "main" io.jsonwebtoken.security.WeakKeyException: The signing key's size is 40 bits which is not secure enough for the HS256 algorithm.  The JWT JWA Specification (RFC 7518, Section 3.2) states that keys used with HS256 MUST have a size >= 256 bits (the key size must be greater than or equal to the hash output size).  Consider using the io.jsonwebtoken.security.Keys class's 'secretKeyFor(SignatureAlgorithm.HS256)' method to create a key guaranteed to be secure enough for HS256.  See https://tools.ietf.org/html/rfc7518#section-3.2 for more information.

4、报错缺少序列化的包
Exception in thread "main" io.jsonwebtoken.lang.UnknownClassException: Unable to find an implementation for interface io.jsonwebtoken.io.Serializer using java.util.ServiceLoader. Ensure you include a backing implementation .jar in the classpath, for example jjwt-impl.jar, or your own .jar for custom implementations.

5、jwt官网可以base64解密出来

6、可以看到生成的jwt串,用点分割成了3部分
前两部分是base64编码,最后一部分是md5。

7、jwt官网可以base64解密出来

三、jwt底层组成部分

1、header(头部)
记录令牌类型、签名算法等。
{
  "type":"jwt"  --类型为jwt
  "alg":"HS256"  --加密算法为HS256
}
在header中描述jwt的payload的加密方式。

2、payload(载荷)
携带一些用户信息。
装载的数据,用户名称、用户头像之类,注意敏感数据不能存放。
标准中注册的声明:
iss:jwt签发者
sub:jwt所面向的用户
aud:接收jwt的一方
exp:jwt的过期时间,这个过期时间必须要大于签发时间
nbf:定义在什么时间之前,该jwt都是不可用的
iat:jwt的签发时间
jti:jwt的唯一身份标识,主要用来作为一次性token,从而避免重放攻击

3、signature(签名)
防止篡改payload中的数据,确保安全性。

4、jwt与token最大的区别
token依赖于redis查询数据信息,token存放value数据比较安全。
jwt不需要依赖于服务器端,将数据内容直接存放在客户端(浏览器)。

四、jwt优缺点

1、优点
(1)无需在服务器存放用户的数据,减轻服务器端压力
(2)轻量级、json风格比较简单
(3)跨语言

2、缺点
(1)token一旦生成,后期无法修改
(2)无法更新token有效期
(3)无法销毁一个token

五、jwt解密
1、JWTDemo02.java

package myboot;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;

public class JWTDemo02 {

	public static void main(String[] args) {
		//jwt秘钥
		String signKey = "test123test123test123test123test123test123test123";
		String jwt = "eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI2NiIsInN1YiI6InRlc3QxMjMiLCJpYXQiOjE2Njc4MDE3MDUsInVzZXJuYW1lIjoiemhhbmdzYW4xMjMxMjMifQ.3wkV3WrPyjxyUs-9E_4-1QcpExE2N14zxFP_MlgAtjQ";
		Claims body = Jwts.parser().setSigningKey(signKey).parseClaimsJws(jwt).getBody();
		System.out.println(body.toString());
	}
}

六、JWT加密和解密原理
1、JWTDemo05.java

package myboot;

import java.io.UnsupportedEncodingException;
import java.util.Base64;

import org.apache.commons.codec.digest.DigestUtils;

import com.alibaba.fastjson.JSONObject;

/**
 * JWT加密原理
 * @author user
 *
 */
public class JWTDemo05 {

	public static void main(String[] args) throws UnsupportedEncodingException {
		//header
		JSONObject header = new JSONObject();
		header.put("alg", "HS256");
		
		//payload
		JSONObject payLoad = new JSONObject();
		payLoad.put("userName", "zhangsan123123");
		payLoad.put("userAge", "21");
		
		//base64编码
		String jwtHeader = Base64.getEncoder().encodeToString(header.toJSONString().getBytes());
		String jwtPayLoad = Base64.getEncoder().encodeToString(payLoad.toJSONString().getBytes());
		
		String signKey = "test123test123test123test123test123test123test123";
		//签名,后面再加盐
		String sign = DigestUtils.md5Hex(payLoad.toJSONString() + signKey);
		
		String jwt = jwtHeader + "." + jwtPayLoad + "." + sign;
		System.out.println(jwt);
		
		/**
		 * 解密
		 */
		String str[] = jwt.split("\\.");
		String headerStr = new String(Base64.getDecoder().decode(str[0]), "UTF-8");
		String payLoadStr = new String(Base64.getDecoder().decode(str[1]), "UTF-8");
		String signStr = str[2];
		
		System.out.println(DigestUtils.md5Hex(payLoadStr + signKey).equals(signStr));
	}
}

执行结果可以在官网验证成功:

七、jwt如何实现注销
1、浏览器cookie清除(但是服务器还是存在)
2、建议将时间设置稍微短一点
3、jwt有效期90天,要提前过期,无法实现
无状态的token,服务端不保存,收到token后通过一套加密验证算法(或其他策略)来确定你的token是否合法。
4、黑名单过滤
 

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值