JWT令牌:实现安全会话跟踪与登录认证的利器

news2025/5/30 13:22:14

摘要:本文深入探讨了JWT令牌在实现会话跟踪和登录认证方面的应用,详细介绍了JWT令牌的概念、组成、生成与校验方法,以及在实际案例中如何通过JWT令牌进行会话跟踪和登录认证的具体实现步骤,为系统的安全认证机制提供了全面且深入的技术指导。

关键词:JWT令牌;会话跟踪;登录认证;生成与校验
参考资料:黑马程序员day12 完整项目请从第10天开始看

一、引言

在基于令牌技术实现会话追踪的背景下,本文着重介绍功能强大的JWT令牌,它作为用户身份标识,以字符串形式存在。接下来将详细阐述JWT令牌的相关知识及在项目中的具体应用。

二、JWT令牌

2.1 介绍

JWT,全称JSON Web Token,官网为https://jwt.io/ 。它定义了一种简洁且自包含的格式,用于在通信双方以json数据格式安全传输信息,凭借数字签名确保信息可靠。

  • 简洁性:JWT表现为简单字符串,可在请求参数或请求头中直接传递。
  • 自包含性:虽看似随机字符串,但可按需求在其中存储自定义数据,如用户相关信息。本质上,JWT是对原始json数据格式进行安全封装,实现通信双方的安全信息传输。

JWT令牌由三部分组成,各部分间以英文点号分隔:

  • Header(头):记录令牌类型、签名算法等信息,例如:{“alg”:“HS256”,“type”:“JWT”} 。
  • Payload(有效载荷):携带自定义信息、默认信息等,例如:{“id”:“1”,“username”:“Tom”} 。
  • Signature(签名):用于防止Token被篡改,确保安全性。它通过将header、payload与指定秘钥结合,运用指定签名算法计算得出。签名机制使得JWT令牌极为安全可靠,一旦令牌中任何部分被篡改,校验时便会失败。

生成JWT令牌时,会对JSON格式数据进行base64编码。Base64是基于64个可打印字符表示二进制数据的编码方式,使用的字符包括A - Z、a - z、0 - 9、加号、斜杠,共64个字符,另加等号作为补位符号。需注意,Base64是编码方式,并非加密方式。

JWT令牌典型应用场景为登录认证,流程如下:

  1. 浏览器发起登录请求,访问登录接口,若登录成功,生成JWT令牌并返回给前端。
  2. 前端接收JWT令牌后存储,后续每次请求将其携带至服务端
  3. 服务端统一拦截请求,判断是否携带令牌。若无令牌,拒绝访问;若有令牌,校验其有效性,有效则放行处理请求。

2.2 生成和校验

为在Java代码中生成和校验JWT令牌,首先需引入JWT依赖:

<!-- JWT依赖-->
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.1</version>
</dependency>

引入依赖后,可借助工具类Jwts提供的API完成操作。

  • 生成JWT代码实现
@Test
public void genJwt(){
    Map<String,Object> claims = new HashMap<>();
    claims.put("id",1);
    claims.put("username","Tom");

    String jwt = Jwts.builder()
      .setClaims(claims) //自定义内容(载荷)          
      .signWith(SignatureAlgorithm.HS256, "itheima") //签名算法        
      .setExpiration(new Date(System.currentTimeMillis() + 24*3600*1000)) //有效期   
      .compact();

    System.out.println(jwt);
}

运行上述测试方法,输出的结果即为生成的JWT令牌。可将令牌复制至JWT官网,粘贴于Encoded位置,自动解析令牌。解析后,第一部分显示所用签名算法为HS256;第二部分为自定义数据及设置的过期时间(exp),因前两部分采用base64编码,可直接解码;第三部分由签名算法计算得出,无法直接解析。https://jwt.io/#debugger-io
在这里插入图片描述

校验JWT令牌(解析生成的令牌)

@Test
public void parseJwt(){
    Claims claims = Jwts.parser()
      .setSigningKey("itheima")//指定签名密钥(必须保证和生成令牌时使用相同的签名密钥)  
      .parseClaimsJws("eyJhbGciOiJIUzI1NiJ9.eyJpZCI6MSwiZXhwIjoxNjcyNzI5NzMwfQ.fHi0Ub8npbyt71UqLXDdLyipptLgxBUg_mSuGJtXtBk")
      .getBody();

    System.out.println(claims);
}

运行该测试方法,若解析过程未报错,说明解析成功,可看到解析出的id和过期时间。若篡改令牌(如修改header中的数字),解析时会报错,表明JWT令牌被篡改。此外,修改生成令牌时设置的过期时间,过期后再解析也会报错,说明JWT令牌过期后失效。

使用JWT令牌时需注意:

  • JWT校验所用签名秘钥必须与生成JWT令牌时的秘钥配套。
  • 若JWT令牌解析校验报错,则表明令牌被篡改或已失效,即令牌非法。

2.3 登录下发令牌

完成JWT令牌生成和校验的基础学习后,着手在案例中运用JWT令牌技术跟踪会话,主要包含生成令牌和校验令牌两步。首先实现登录成功后生成JWT令牌并返回给前端。

查看登录接口文档的响应数据部分可知,登录成功后系统下发JWT令牌,后续请求需在请求头header中以“token”为名称,携带登录时下发的JWT令牌。若检测到用户未登录,返回固定错误信息。

实现步骤

  • 引入JWT工具类:在项目工程下创建com.itheima.utils包,并将提供的JWT工具类复制到该包下。
  • 登录完成后,调用工具类生成JWT令牌并返回

JWT工具类

public class JwtUtils {

    private static String signKey = "itheima";//签名密钥
    private static Long expire = 43200000L; //有效时间

    /**
     * 生成JWT令牌
     * @param claims JWT第二部分负载 payload 中存储的内容
     * @return
     */
    public static String generateJwt(Map<String, Object> claims){
        String jwt = Jwts.builder()
                .addClaims(claims)//自定义信息(有效载荷)
                .signWith(SignatureAlgorithm.HS256, signKey)//签名算法(头部)
                .setExpiration(new Date(System.currentTimeMillis() + expire))//过期时间
                .compact();
        return jwt;
    }

    /**
     * 解析JWT令牌
     * @param jwt JWT令牌
     * @return JWT第二部分负载 payload 中存储的内容
     */
    public static Claims parseJWT(String jwt){
        Claims claims = Jwts.parser()
                .setSigningKey(signKey)//指定签名密钥
                .parseClaimsJws(jwt)//指定令牌Token
                .getBody();
        return claims;
    }
}

登录成功,生成JWT令牌并返回

@RestController
@Slf4j
public class LoginController {
    //依赖业务层对象
    @Autowired
    private EmpService empService;

    @PostMapping("/login")
    public Result login(@RequestBody Emp emp) {
        //调用业务层:登录功能
        Emp loginEmp = empService.login(emp);

        //判断:登录用户是否存在
        if(loginEmp !=null ){
            //自定义信息
            Map<String , Object> claims = new HashMap<>();
            claims.put("id", loginEmp.getId());
            claims.put("username",loginEmp.getUsername());
            claims.put("name",loginEmp.getName());

            //使用JWT工具类,生成身份令牌
            String token = JwtUtils.generateJwt(claims);
            return Result.success(token);
        }
        return Result.error("用户名或密码错误");
    }
}

签名算法大致分类

对称加密算法

  • HS256(HMAC with SHA - 256):使用 HMAC(Hash - based Message Authentication Code)算法结合 SHA - 256 哈希函数。在使用 HS256 算法时,服务器端和客户端共享一个相同的密钥(secret)。服务器使用该密钥和 HS256 算法对头部和载荷进行签名生成
    JWT。客户端收到 JWT 后,使用相同的密钥和算法重新计算签名,并与 JWT 中的签名进行对比,若一致则说明 JWT 未被篡改。
  • HS384(HMAC with SHA - 384):类似于 HS256,只是使用了 SHA - 384 哈希函数,提供更高的安全性,但计算成本也相对较高。
  • HS512(HMAC with SHA - 512):使用 SHA - 512 哈希函数,安全性更高,但计算开销也更大,适用于对安全性要求极高的场景。

非对称加密算法

  • RS256(RSA Signature with SHA - 256):基于 RSA(Rivest - Shamir - Adleman)非对称加密算法和 SHA - 256 哈希函数。服务器使用私钥对头部和载荷进行签名生成 JWT,客户端使用对应的公钥来验证签名。这种方式无需在客户端和服务器之间共享密钥,提高了安全性,常用于分布式系统或对安全性要求较高的场景。
  • RS384(RSA Signature with SHA - 384):使用 RSA 算法结合 SHA - 384 哈希函数。
  • RS512(RSA Signature with SHA - 512):使用 RSA 算法结合 SHA - 512 哈希函数。

椭圆曲线算法

  • ES256(Elliptic Curve Signature with SHA - 256):基于椭圆曲线密码学(ECC)和 SHA - 256 哈希函数。与 RSA 相比,椭圆曲线算法在相同的安全强度下,密钥长度更短,计算速度更快,适用于对性能要求较高且对安全性有一定要求的移动设备或资源受限的环境。
  • ES384(Elliptic Curve Signature with SHA - 384):使用椭圆曲线算法结合 SHA - 384 哈希函数。
  • ES512(Elliptic Curve Signature with SHA - 512):使用椭圆曲线算法结合 SHA - 512 哈希函数。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2336231.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

springboot+tabula解析pdf中的表格数据

场景 在日常业务需求中&#xff0c;往往会遇到解析pdf数据获取文本的需求&#xff0c;常见的做法是使用 pdfbox 来做&#xff0c;但是它只适合做一些简单的段落文本解析&#xff0c;无法处理表格这种复杂类型&#xff0c;因为单元格中的文本有换行的情况&#xff0c;无法对应到…

阿里FPGA XCKU3P开箱- 25G 光纤

阿里FPGA XCKU3P开箱 - Hello-FPGA - 博客园 25G 光纤 板子有2个SFP的光纤接口&#xff0c;最大支持25G速率&#xff0c;使用ibert 进行验证&#xff0c;SFP在BANK227的GTY 接口。 ibert 配置如下&#xff1a; 测试 测试符合预期&#xff0c;确认了SFP的具体位置 和 支持的速…

.NET Core DI(依赖注入)的生命周期及应用场景

在.NET中&#xff0c;依赖注入&#xff08;DI&#xff0c;Dependency Injection&#xff09;是一种设计模式&#xff0c;它通过将依赖关系注入到类中&#xff0c;而不是让类自己创建依赖项&#xff0c;来降低类之间的耦合度。这使得代码更加模块化、灵活和易于测试。在.NET中&a…

新技术学习方法

新技术学习方法 学习新技术的路线需要结合系统性规划与实践验证&#xff0c;以下是基于行业经验和学习科学整理的高效路径框架&#xff0c;适用于编程语言、开发框架、前沿技术等领域&#xff1a; 一、明确学习目标与动机&#xff08;战略层&#xff09; 场景化需求分析 明确…

内网dns权威域名服务器搭建

目录 一、背景 二、dns简介 1、dns服务器类型 1、缓存域名服务器 2、主域名服务器 3、从域名服务器 2、dns解析过程 1、递归查询 2、迭代查询&#xff1a; 3、dns服务器类型 1、根域名服务器 2、顶级域名服务器 顶级域名可分为两类 顶级域名服务器的重要性体现在…

爱普生SG2520VGN差分晶振5G基站的时钟解决方案

在 5G 通信时代&#xff0c;数据流量呈爆发式增长&#xff0c;5G 基站作为信号的核心中转枢纽&#xff0c;承载着前所未有的数据传输与处理重任。从海量的物联网设备连接&#xff0c;到高速移动用户的数据交互&#xff0c;每一个环节都对基站的性能提出了严苛要求。而精准稳定的…

Linux中设置文件开机自启

###方法有很多&#xff0c;这里只分享一个systemd的方法 1.创建service文件 在/etc/systemd/system/下创建&#xff0c;自己命名&#xff0c;后缀是.service 创建方式有两种&#xff1a; 进入/etc/systemd/system创建&#xff0c;创建后使用sudo vim编辑使用sudo nano /etc/…

AWTK-MVVM 如何让多个View复用一个Model记录+关于app_conf的踩坑

前言 有这么一个业务&#xff0c;主界面点击应用窗口进入声纳显示界面&#xff0c;声纳显示界面再通过按钮进入菜单界面&#xff0c;菜单界面有很多关于该声纳显示界面的设置项&#xff0c;比如量程&#xff0c;增益&#xff0c;时间显示&#xff0c;亮度&#xff0c;对比度等…

kotlin音乐之自定义唱片组件(简单版本)

代码地址 import android.animation.ObjectAnimator import android.animation.ValueAnimator import android.content.Context import android.os.Binder import android.util.AttributeSet import android.view.animation.LinearInterpolator import androidx.appcompat.widg…

Redis 版本变更的变化

Redis 版本变更的变化 以下是 Redis 主要版本的清单及其核心功能变化的梳理&#xff0c;按时间顺序整理关键版本演进 8版本没有整理&#xff1a; Redis 1.0 (2009) 初始版本&#xff1a;发布首个稳定版本&#xff0c;支持基本键值存储。 核心特性&#xff1a; 支持字符串&…

文本纠错WPS插件:提升文档质量的利器

文本纠错WPS插件&#xff1a;提升文档质量的利器 引言 在数字化办公日益普及的今天&#xff0c;文档的质量直接影响到我们的工作效率和形象。一个错别字或标点错误&#xff0c;可能就会让我们的专业形象大打折扣。今天&#xff0c;我要向大家介绍一款强大的WPS插件——文本纠…

多光谱相机与高光谱相机的区别

多光谱相机与高光谱相机均属于光谱成像设备&#xff0c;但两者在‌光谱分辨率、波段数量、数据维度及应用场景‌上存在显著差异。以下是详细的对比分析&#xff1a; ‌一、核心差异对比 二、工作原理差异‌ ‌多光谱相机‌ ‌波段选择‌&#xff1a;根据目标物特性‌预设特定…

MVCC详细介绍及面试题

目录 1.什么是mvcc&#xff1f; 2.问题引入 3. MVCC实现原理&#xff1f; 3.1 隐藏字段 3.2 undo log 日志 3.2.1 undo log版本链 3.3 readview 3.3.1 当前读 ​编辑 3.3.2 快照读 3.3.3 ReadView中4个核心字段 3.3.4 版本数据链访问的规则&#xff08;了解&#x…

电商企业如何实现流程精细化?日事清「标准化+可视化+自动化」全流程管理实战解析​

电商企业在业务快速发展中&#xff0c;往往会遇到如下问题&#xff1a; 1、店铺多款产品需要上新维护&#xff0c;但工作重点往往不清晰&#xff0c;员工经常忘记&#xff0c;没做也不当回事&#xff1b; 2、员工做事经常错漏细节&#xff0c;犯低级错误&#xff1b; 3、人员…

威锋VL822-Q7T10GHUB芯片适用于扩展坞显示器

一、概述 VL822-Q7T是VIA Lab&#xff08;威盛电子旗下专注于USB相关技术研发的子公司&#xff09;精心打造的一款高性能USB 3.1 Gen2集线器控制器芯片。在当今数字化时代&#xff0c;USB接口作为设备连接与数据传输的核心通道&#xff0c;其性能与稳定性至关重要。VL822-Q7T凭…

交换机与路由器的默契配合:它们的联系与区别

交换机与路由器的默契配合&#xff1a;它们的联系与区别 一. 交换机与路由器的基本功能1.1 交换机的功能1.2 路由器的功能 二. 交换机和路由器的区别三. 交换机和路由器的联系3.1 数据转发的协作3.2 网络分段与分隔3.3 协同工作提供互联网接入 四. 交换机和路由器的联合应用场景…

Redis 分布式锁+秒杀异步优化

文章目录 问题思路setnx实现锁误删问题和解决方案Redis Lua脚本问题引出解决方案 setnx实现的问题Redission快速入门redission可重入锁原理 秒杀优化(异步优化)异步秒杀思路秒杀资格判断Redis消息队列 问题 比如我们两个机器都部署了我们项目&#xff0c;这里nginx使用轮询的方…

Git_获取GitLab的token方法(访问令牌)

一、操作步骤 GitLab-获取token&#xff08;访问令牌&#xff09;主要步骤&#xff1a;以及相关截图 登录 GitLab 打开 GitLab 网站并登录你的账号。 进入用户设置 点击右上角头像 → Edit profile → 左侧菜单选择 Access Tokens。 创建 Token Token name: 输入名称&#…

【生活相关-日语-日本-东京-留学生-搬家后或新入驻-水道局申请饮用水(1)-办理手续】

【生活相关-日语-日本-东京-搬家后-水道局申请饮用水-办理手续】 1、前言2、情况说明&#xff08;1&#xff09;他人代办&#xff08;2&#xff09;打电话&#xff08;3&#xff09;网络申请&#xff08;4&#xff09;你将会面临什么&#xff0c;主要步骤&#xff08;5&#xf…

【C语言】--- 预处理详解

预处理详解 1. 预定义符号2. define定义常量2. define 定义宏4. 带有副作用的宏参数5.宏替换的规则6. 宏和函数的对比7. # 和 \##7.1#运算符 7.2 \##运算符8. 命名约定9.#undef10.命令行定义11.条件编译12. 头文件的包含12.1 头文件被包含的方式12.1.1 头文件的本地包含12.1.2 …