JWT概念及JAVA使用

embedded/2025/3/5 21:39:14/

前言

  • JSON Web Token(缩写 JWT)是目前最流行的跨域认证解决方案

认证方式

认证方式一般有两种

  1. session认证
  2. JWT认证

一、session认证

1、步骤

过去,我们都是使用session认证,步骤如下

  1. 前端访问登录接口
  2. 登录接口验证完账号密码没问题时,在redis中插入一条数据session_id:用户信息,表示这个session_id登录了,然后将这个session_id`返回给前端
  3. 前端接收到session_id后,放入Cookie中,在后续请求接口中自动带上。
  4. 后续接口在收到Cookie时,拿着session_id去查询Redis,获得用户登录身份
    1. 未查询到:返回前端一个状态码,前端跳转到登录页
    2. 查到了:执行正常逻辑,并且返回给前端数据
  5. 登出时:可以让后端将这个session_idredis中删了即可

在这里插入图片描述

2、优劣势

  • 优势:无
  • 劣势:
    1. 如果用户数据量大,那么内存压力也会相应变大
    2. 如果多个微服务,那么需要远程调用登录服务校验,或者每个服务都需要连接这个Redis,并且重复编写请求拦截校验代码

二、JWT认证

1、步骤

  1. 用户访问登录接口
  2. 登录成功后,后端根据JWT提供的方法,设置Header(头部),payload(负载),Signature(签名)
  3. 将生成的结果返回给前端,前端保存到sessionStorage/localStorage中,每次请求带上这个值,放入header
  4. 后端接受到后,直接使用JWT提供的方法,校验根据.签名两个值生成的签名与生成签名时的密钥是否一致

2、生成签名公式

  • Header:有令牌的类型和所使用的签名算法,如HMAC、SHA256、RSA;使用Base64编码组成;(Base64是一种编码,不是一种加密过程,可以被翻译成原来的样子)

    Base64URL({"alg":"HS256","typ":"JWT"})
    
  • Payload:有效负载,包含声明;声明是有关实体(通常是用户)和其他数据的声明,不放用户敏感的信息,如密码。同样使用Base64编码

    Base64URL({"id":1,"name":"张三","username":"zhangSan"
    })
    
  • Signature:前面两部分都使用Base64进行编码,前端可以解开知道里面的信息。Signature需要使用编码后的header和payload
    加上我们提供的一个密钥,使用header中指定的签名算法(HS256)进行签名。签名的作用是保证JWT没有被篡改过

    HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret(密钥,只有服务器知道))
    
  • 签名:签名的过程实际上是对头部以及负载内容进行签名,防止内容被窜改。如果有人对头部以及负载的内容解码之后进行修改,再进行编码,最后加上之前的签名组合形成新的JWT的话,那么服务器端会判断出新的头部和负载形成的签名和JWT附带上的签名是不一样的。如果要对新的头部和负载进行签名,在不知道服务器加密时用的密钥的话,得出来的签名也是不一样的

3、代码实践

  • 我这里将JWT所有操作生成Token,校验Token,获取Payload中信息统一提取到JwtTokenUtil类中
java">package com.tcc.utils;import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.AlgorithmMismatchException;
import com.auth0.jwt.exceptions.InvalidClaimException;
import com.auth0.jwt.exceptions.SignatureVerificationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.sun.org.apache.xml.internal.security.algorithms.SignatureAlgorithm;import java.util.Date;public class JwtTokenUtil {// 密钥private static final String SECRET = "123456";// 一天毫秒数private static final long EXPIRE_TIME = 24 * 60 * 60 * 1000;/*** 获取Token* @Author: tcc* @Date: 2025/3/1 16:17*/public static String getToken() {return  JWT.create().withClaim("id", "1") // Payload 用户信息.withClaim("name", "张三") // Payload 用户信息.withClaim("username", "zhangSan").withExpiresAt(new Date(System.currentTimeMillis() + EXPIRE_TIME)) // 过期时间,一天.sign(Algorithm.HMAC256(SECRET));}/*** 校验Token* @Author: tcc* @Date: 2025/3/1 16:21*/public static void validateToken(String token) {try {JWT.require(Algorithm.HMAC256(SECRET)).build().verify(token);System.out.println("验证成功");} catch (Exception e) {e.printStackTrace();System.out.println("验证失败");}// ExpiredJwtException:当 JWT 的过期时间(exp 声明)已过,验证时就会抛出此异常// SignatureException:当 JWT 的签名验证失败时,会抛出该异常。这可能是因为 token 被篡改,或者使用了错误的密钥进行验证。// MalformedJwtException 当 JWT 的格式不正确时,例如 token 不是一个有效的 JWT 字符串,或者不满足 JWT 的结构(由头部、载荷和签名三部分组成,用 . 分隔),就会抛出此异常。// UnsupportedJwtException:当 JWT 使用了不支持的签名算法,或者 token 包含不支持的类型、声明等时,会抛出此异常// IllegalArgumentException: 当 token 为 null 或者为空字符串时,就会抛出此异常}/*** 获取 payload 信息* @Author: tcc* @Date: 2025/3/1 16:23*/public static void getPayload(String token) {DecodedJWT verify = JWT.require(Algorithm.HMAC256(SECRET)).build().verify(token);System.out.println(verify.getExpiresAt()); // 获取 过期时间System.out.println();verify.getClaims().forEach((key, value) -> {System.out.println(key + ":" + value.asString());});}
}

测试代码

java">package com.tcc.controller;import com.tcc.utils.JwtTokenUtil;
import org.junit.jupiter.api.Test;
import org.springframework.web.bind.annotation.RestController;@RestController
public class TestController {@Testvoid login() {// ------- 验证账号密码 省略 -------// 通过 每次都会随机生成,但是每个都可以校验成功System.out.println(JwtTokenUtil.getToken());}@Testvoid validateToken() {// 根据上面token复制而来String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoi5byg5LiJIiwiaWQiOiIxIiwiZXhwIjoxNzQwOTA0NjgyLCJ1c2VybmFtZSI6InpoYW5nU2FuIn0.8XickAlHQI14v9SE-z_GDDpr5Oed8fVcuw4UAetccdY";JwtTokenUtil.validateToken(token);}@Testvoid getPayload() {String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoi5byg5LiJIiwiaWQiOiIxIiwiZXhwIjoxNzQwOTA0NjgyLCJ1c2VybmFtZSI6InpoYW5nU2FuIn0.8XickAlHQI14v9SE-z_GDDpr5Oed8fVcuw4UAetccdY";JwtTokenUtil.getPayload(token);}
}

效果

在这里插入图片描述

三、总结

  • JWT默认是不加密的payload里面内容也是根据Base64URL编码转化了一下,并没有加密,所以不能存放密码等信息,当然也可以在生成原始Token的时候再加密一次
  • JWT最大的缺点是:由于服务器不保存session状态,当前端登出操作时,无法废除Token,也就是说,一旦Token签发了,再到期之前就会始终有效
    • 解决办法:
      1. 登出时,前端删除Token信息即可
      2. 登陆成功后返回前端时间较短的accessToken,以及一个时间较长的refreshToken(用来重新获取token),前端清除refreshToken后则无法获取新token
  • JWT本身包含了认证信息,一旦泄露,任何人都可以获得该令牌的所有权限。为了减少盗用,JWT 的有效期应该设置得比较短。对于一些比较重要的权限,使用时应该再次对用户进行认证。

http://www.ppmy.cn/embedded/170300.html

相关文章

Linux与UDP应用1:翻译软件

UDP应用1:翻译软件 本篇介绍 本篇基于UDP编程接口基本使用中封装的服务器和客户端进行改写,基本功能如下: 从配置文件dict.txt读取到所有的单词和意思客户端向服务端发送英文服务端向客户端发送英文对应的中文意思 配置文件内容 下面的内…

大白话React Hooks(如 useState、useEffect)的使用方法与原理

啥是 React Hooks 在 React 里,以前我们写组件主要用类(class)的方式,写起来有点复杂,尤其是处理状态和副作用的时候。React Hooks 就是 React 16.8 之后推出的新特性,它能让我们不用写类,直接…

211.SpringSecurity:认证、授权概念,自定义数据源认证,验证码认证

目录 一、权限管理概念 1.基本概念 2.常用权限管理解决方案 (1)Shiro (2)Spring Security 二、整体架构 1.认证:Authentication (1)AuthenticationManager (2)Authentication (3)SecurityContextHolder 2.授权:Authorization (1)AccessDecisionManag…

面试常问的压力测试问题

性能测试作为软件开发中的关键环节,确保系统在高负载下仍能高效运行。压力测试作为性能测试的重要类型,旨在通过施加超出正常负载的压力,观察系统在极端条件下的表现。面试中,相关问题常被问及,包括定义、重要性、与负…

计算机毕设JAVA——某高校宿舍管理系统(基于SpringBoot+Vue前后端分离的项目)

文章目录 概要项目演示图片系统架构技术运行环境系统功能简介 概要 网络上许多计算机毕设项目开发前端界面设计复杂、不美观,而且功能结构十分单一,存在很多雷同的项目:不同的项目基本上就是套用固定模板,换个颜色、改个文字&…

大模型的实践应用36-基于AI Agent和通义千问大模型,支持多轮问答的智能问数和数据分析的应用场景

大家好,我是微学AI,今天给大家介绍一下大模型的实践应用36基于AI Agent和通义千问大模型,支持多轮问答的智能问数和数据分析的应用场景。 文章目录 一、整体框架功能概述(一)深度解析多轮对话在数据查询需求确定中的关键作用(二)明确查询相关要素的重要性框架结构(一)…

Redis数据库面试——数据结构类型知识

大家好,这里是Good Note,关注 公主号:Goodnote,专栏文章私信限时Free。本文详细介绍Redis 提供的5种基本数据结构类型和4种特殊类型,除此之外,还有8种底层数据结构,每种结构类型有其特点和适用场…

19.4-STM32接收数据-状态显示在屏幕

功能介绍放开头, 使用便捷无需愁 这是全网最详细、性价比最高的STM32实战项目入门教程,通过合理的硬件设计和详细的视频笔记介绍,硬件使用STM32F103主控资料多方便学习,通过3万字笔记、12多个小时视频、20多章节代码手把手教会你…