【图文详解】JWT从入门到精通,与Cookie、Session、Token的全面对比分析

前言

在现代Web开发中,身份认证是一个永恒的话题。随着前后端分离架构的流行,JWT(JSON Web Token)逐渐成为身份认证的主流方案。本文将通过图文方式,深入解析JWT的原理,并与传统的Cookie、Session、Token进行全面对比。

一、JWT是什么?

JWT(JSON Web Token)是一种开放标准(RFC 7519),用于在网络应用间安全传输信息。它是一个紧凑、自包含的JSON对象,主要用于身份认证和信息交换。

1.1 JWT的三大特点

  • 无状态:服务器不需要保存会话信息

  • 自包含:包含了所有必要的信息

  • 可扩展:支持分布式系统

1.2 JWT的优缺点分析

✅ 优点:

  1. 无状态:服务器不需要保存会话信息,易于扩展

  2. 跨域支持:支持CORS,适合前后端分离

  3. 自包含:包含了所有必要信息,减少数据库查询

  4. 标准化:行业标准,支持多种语言

❌ 缺点:

  1. 无法强制失效:一旦签发,到期前始终有效

  2. 载荷大小有限:不宜存储过多信息

  3. 安全性依赖实现:需要正确配置签名算法

  4. 不适合存储敏感信息:Payload只是Base64编码

二、JWT的结构详解

JWT由三部分组成,用点(.)分隔:

JWT结构:Header.Payload.Signature

2.1 Header(头部)

包含令牌的类型和使用的签名算法:

javascript 复制代码
{
  "alg": "HS256",  ---算法为HS256
  "typ": "JWT"  ---类型为jwt
}

2.2 Payload(载荷)

包含声明信息(用户数据),想写几个写几个,该内容会被解码,建议不要使用敏感信息:

javascript 复制代码
{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true,
  "exp": 1516239022
}

2.3 Signature(签名)

用于验证消息的完整性和真实性,防止串改payload中的数据,且该部分无法被解码:

组成为:header加密+payload加密+秘钥

javascript 复制代码
HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret
)

三、JWT工作流程

四、JWT 、Cookie 、Session 、Token 对比

4.1 概念对比表

4.2 安全性对比

4.3 实际适合场景推荐

五、springboot实践案例

5.1 在pom.xml加依赖

XML 复制代码
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.6.0</version>
        </dependency>

若jdk版本在1.8以上的话,还需要加上下面的依赖:

XML 复制代码
        <dependency>
            <groupId>com.sun.bind</groupId>
            <artifactId>jaxb.api</artifactId>
            <version>2.3.0</version>
        </dependency>
        <dependency>
            <groupId>com.sun.bind</groupId>
            <artifactId>jaxb.impl</artifactId>
            <version>2.3.0</version>
        </dependency>
        <dependency>
            <groupId>com.sun.xml.bind</groupId>
            <artifactId>jaxb-core</artifactId>
            <version>2.3.0</version>
        </dependency>
        <dependency>
            <groupId>javax.activation</groupId>
            <artifactId>activation</artifactId>
            <version>1.1.1</version>
        </dependency>

5.2 创建工具类JwtUtil

java 复制代码
public class JwtUtil {

    //    private static long tokenExpiration = 1000 * 60 * 60 * 24;
    private static long tokenExpiration = 1000 * 20;
    private static String tokenSignKey = "a1d23mi789n";

    public static String createToken(String id,String mobile){
        String token = Jwts.builder()
                //载荷:自定义信息
                .claim("id", id)
                .claim("mobile", mobile)
                //载荷:默认信息
                .setSubject("uushop-user") //令牌主题
                .setExpiration(new Date(System.currentTimeMillis()+tokenExpiration)) //过期时间
                .setId(UUID.randomUUID().toString())
                //签名哈希
                .signWith(SignatureAlgorithm.HS256, tokenSignKey)
                //组装jwt字符串
                .compact();
        return token;
    }

    public static boolean checkToken(String token){
        if(StringUtils.isEmpty(token)){
            return false;
        }
        try {
            Jws<Claims> claimsJws = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token);
        } catch (Exception e) {
            return false;
        }
        return true;
    }
}

5.3 创建实体类

java 复制代码
@Data //若要使用该注解需要添加lombok依赖
public class User {
private String username;
private String password;
private String token;
}

5.4 创建UserController类

java 复制代码
@RestController
public class UserController {
private final String USERNAME = "admin";
private final String PASSWORD = "123123";
@GetMapping("/login")
public User login(User user){
if(USERNAME.equals(user.getUsername())&&PASSWORD.equals(user.getPassword())){
//添加token
user.setToken(JWTUtil.createToken());
return user;
}
return null;
}

//将token值传给前端,前端的点击登录事件中,通过
localStorage.setItem("token",JSON.stringify(response.data))将token值进行保存,并进行路由的
跳转,
// 在登录时如果该用户不存在,则返回登录界面,
// 如果用户存在则前端即将进入的页面里面通过以下代码:
// created(){window.localStorage.getItem("token")}将token值取出来通过将token值然后传给
后端
//同时,将token存在前端的路由index.js文件中的axios中的header中的token中
//后端将前端传过来的token值进行校验

@GetMapping("/checkToken")
public Boolean checkToken(HttpServletRequest request){
String token = request.getHeader("token");
return JWTUtil.checkToken(token);
}
}

一般工作中都是要结合redis使用的。大家可以探索一下。

💬 欢迎留言讨论: 你在项目中是如何选择认证方案的?遇到过哪些JWT相关的问题?欢迎在评论区分享你的经验!

相关推荐
washingtin5 小时前
Get “https://registry-1.docker.io/v2/“: context deadline exceeded
java·开发语言
only-lucky5 小时前
Python版本OpenCV
开发语言·python·opencv
三万棵雪松5 小时前
【python-基础】
开发语言·python
一路往蓝-Anbo5 小时前
C语言从句柄到对象 (七) —— 给对象加把锁:RTOS 环境下的并发安全
java·c语言·开发语言·stm32·单片机·嵌入式硬件·算法
先做个垃圾出来………5 小时前
2610.转换二维数组
开发语言·python
利刃大大5 小时前
【SpringBoot】validation参数校验 && JWT鉴权实现 && 加密/加盐
java·spring boot·jwt·加密
天下皆白_唯我独黑5 小时前
php -S 启动项目访问路由报错处理
开发语言·php
清水迎朝阳5 小时前
Qt 小白成长系列 1-- 官方 文本搜索示例解析
开发语言·qt
小北方城市网5 小时前
第 3 课:前后端全栈联动核心 —— 接口规范 + AJAX + 跨域解决(打通前后端壁垒)
java·大数据·网络·python
Joe_Blue_025 小时前
Matlab入门案例介绍—常用的运算符及优先级
开发语言·数据结构·matlab·matlab基础入门案例介绍