Session、cookie、Token可看:session、cookie、token 详解
一、传统的Token
传统的token(也叫令牌)
jwt只是生成token用的
传统的Token,例如:用户登录成功生成对应的令牌,key为令牌 value:userid,隐藏了数据真实性 ,同时将该token存放到redis中,返回对应的真实令牌给客户端存放。
客户端每次访问后端请求的时候,会传递该token在请求中,服务器端接收到该token之后,从redis中查询如果存在的情况下,则说明在有效期内,如果在Redis中不存在的情况下,则说明过期或者token错误。
二、jwt(json web token)
JSON WEB Token JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。
jwt 官网:
https://jwt.io/
jwt和Token的区别
JWT组成的部分
小demo:
运行后得到了一个jwt:
把这串字符串复制到jwt官网进行解析:
1.Header(头)
作用:记录令牌类型、签名算法等 例如:{“alg":“HS256”,“type”,"JWT}
2.Payload(有效载荷)
作用:
就是存放jwt存放的数据内容
携带一些用户信息 例如
{
“userId”:“1”, //存放在客户端,不安全
“username”:“mayikt”
}
3.Signature(签名)
作用:防止Payload、Token被篡改、确保安全性 例如 计算出来的签名,一个字符串,就算MD5加密而已
1.第一部分:header (头部)
{
Typ=“jwt” —类型为jwt
Alg:“HS256” --加密算法为hs256
}
2.第二部分:playload(载荷) 携带存放的数据 用户名称、用户头像之类 注意铭感数据不要存 标准中注册的声明 (建议但不强制使用) :
iss: jwt签发者
sub: jwt所面向的用户
aud: 接收jwt的一方
exp:jwt的过期时间,这个过期时间必须要大于签发时间
nbf: 定义在什么时间之前,该jwt都是不可用的.
iat: jwt的签发时间
jti:jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。
3.第三部分:Signature(签名)
可能你就会问了,那么别人在你浏览器获取你的payload怎么办?答案:就算你获取了payload那么你也只能模拟,篡改不了的,因为他有签名的:
三、JWT优缺点
优点:
- 无需再服务器存放用户的数据,减轻服务器端压力
- 轻量级、json风格比较简单
- 跨语言
缺点:
jwt一旦生成后期无法修改: - 无法更新jwt有效期
- 无法销毁一个jwt
jwt 90天以后过期 提前60天过期(这种就改不了,因为jwt存在客户端,后期无法修改的。这是Token就有点优势了,因为token存在redis,你只要把redis清除了就可以改了)
四、JWT的应用场景
前端分离项目、(移动app、小程序、H5)
Base64
Base64不是加密和解密 主要是 编码和解码 基于64个可打印字符来表示二进制数据
https://baike.baidu.com/item/base64/8545775?fr=aladdin
https://base64.us/
header 头部:
{
“typ”:“jwt”,
“alg”:“HS256”
}
ewoidHlwIjoiand0IiwKImFsZyI6IkhTMjU2Igp9
playload 存放的数据
{
“userName”:“mayikt”,
“age”:“28”
}
cGxheWxvYWQ=
secret=Base64(header .playload)
https://base64.us/
五、MD5:
六、简单手写jwt 和破解
获取到盐就可以破解了,所以盐一定不要被别人知道
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.codec.digest.Md5Crypt;
import java.io.UnsupportedEncodingException;
import java.util.Base64;
public class JWTDemo04 {
public static void main(String[] args) throws UnsupportedEncodingException {
String jwtSecret="mayikt"; //盐存在服务器中的
// jwt jwtHeader
JSONObject jwtHeader = new JSONObject();
jwtHeader.put