【图文详解】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相关的问题?欢迎在评论区分享你的经验!

相关推荐
鸽鸽程序猿2 小时前
【项目】【抽奖系统】抽奖
java·spring
yue0082 小时前
C# winform自定义控件
开发语言·c#
weixin_462446232 小时前
SpringBoot切换Redis的DB
数据库·spring boot·redis
JANGHIGH3 小时前
c++ 多线程(三)
开发语言·c++
2503_928411563 小时前
12.9 Vue3+Vuex+Js+El-Plus+vite(项目搭建)
开发语言·javascript·ecmascript
GoogleDocs3 小时前
基于[api-football]数据学习示例
java·学习
卓码软件测评3 小时前
第三方软件验收评测机构【Gatling安装指南:Java环境配置和IDE插件安装】
java·开发语言·ide·测试工具·负载均衡
weixin_307779133 小时前
Jenkins中的Jakarta Activation API插件:功能、使用与最佳实践
运维·开发语言·ci/cd·自动化·jenkins
妮妮分享3 小时前
H5获取定位的方式是什么?
java·前端·javascript
Billow_lamb3 小时前
MyBatis-Plus 的 条件构造器详解(超详细版)
java·mybatis