SpringBoot登录校验(三)JWT令牌

SpringBoot 登录认证(一)-CSDN博客

SpringBoot 登录认证(二)-CSDN博客

SpringBoot登录校验(三)-CSDN博客

前面我们介绍了传统的会话跟踪技术cookie和sesstion,本节讲解令牌技术。这里所提到的令牌就是用户身份的标识,其本质就是一个字符串。令牌的形式有很多,我们使用的是功能强大的 JWT令牌。

JWT全称:JSON Web Token (官网:JSON Web Tokens - jwt.io)

  • 定义了一种简洁的、自包含的格式,用于在通信双方以json数据格式安全的传输信息。由于数字签名的存在,这些信息是可靠的。

    简洁:是指jwt就是一个简单的字符串。可以在请求参数或者是请求头当中直接传递。

    自包含:指的是jwt令牌,看似是一个随机的字符串,但是我们是可以根据自身的需求在jwt令牌中存储自定义的数据内容。如:可以直接在jwt令牌中存储用户的相关信息。

    简单来讲,jwt就是将原始的json数据格式进行了安全的封装,这样就可以直接基于jwt在通信双方安全的进行信息传输了。

JWT的组成: (JWT令牌由三个部分组成,三个部分之间使用英文的点来分割)

  • 第一部分:Header(头), 记录令牌类型、签名算法、秘钥(用于签名)等。 例如:{"alg":"HS256","type":"JWT"}

  • 第二部分:Payload(有效载荷),携带一些自定义信息、默认信息等。 例如:{"id":"1","username":"Tom"},其实就是一次会话中多个请求需要共享的数据

  • 第三部分:Signature(签名),防止Token被篡改、确保安全性。将header、payload,并加入指定秘钥,通过指定签名算法计算而来。

    签名的目的就是为了防jwt令牌被篡改,而正是因为jwt令牌最后一个部分数字签名的存在,所以整个jwt 令牌是非常安全可靠的。一旦jwt令牌当中任何一个部分、任何一个字符被篡改了,整个令牌在校验的时候都会失败,所以它是非常安全可靠的。

 

JWT是如何将原始的JSON格式数据,转变为字符串的呢?

其实在生成JWT令牌时,会对JSON格式的数据进行一次编码:进行base64编码

Base64:是一种基于64个可打印的字符来表示二进制数据的编码方式。既然能编码,那也就意味着也能解码。所使用的64个字符分别是A到Z、a到z、 0- 9,一个加号,一个斜杠,加起来就是64个字符。任何数据经过base64编码之后,最终就会通过这64个字符来表示。当然还有一个符号,那就是等号。等号它是一个补位的符号

需要注意的是Base64是编码方式,而不是加密方式。

JWT令牌最典型的应用场景就是登录认证:

  1. 在浏览器发起请求来执行登录操作,此时会访问登录的接口,如果登录成功之后,我们需要生成一个jwt令牌,将生成的 jwt令牌返回给前端。

  2. 前端拿到jwt令牌之后,会将jwt令牌存储起来。在后续的每一次请求中都会将jwt令牌携带到服务端。

  3. 服务端统一拦截请求之后,先来判断一下这次请求有没有把令牌带过来,如果没有带过来,直接拒绝访问,如果带过来了,还要校验一下令牌是否是有效。如果有效,就直接放行进行请求的处理。

在JWT登录认证的场景中我们发现,整个流程当中涉及到两步操作:

  1. 生成令牌。在登录成功之后,服务端要生成令牌,并返回给客户端。

  2. 校验令牌。每一次请求当中,要接收令牌并对令牌进行校验

稍后我们再来学习如何来生成jwt令牌,以及如何来校验jwt令牌。

简单介绍了JWT令牌以及JWT令牌的组成之后,接下来我们就来学习基于Java代码如何生成和校验JWT令牌。

首先我们先来实现JWT令牌的生成。要想使用JWT令牌,需要先引入JWT的依赖:

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

在引入完JWT来赖后,就可以调用工具包中提供的API来完成JWT令牌的生成和校验

工具类:Jwts

生成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);
}

运行测试方法:

eyJhbGciOiJIUzI1NiJ9.eyJpZCI6MSwiZXhwIjoxNjcyNzI5NzMwfQ.fHi0Ub8npbyt71UqLXDdLyipptLgxBUg_mSuGJtXtBk

输出的结果就是生成的JWT令牌,,通过英文的点分割对三个部分进行分割,我们可以将生成的令牌复制一下,然后打开JWT的官网,将生成的令牌直接放在Encoded位置,此时就会自动的将令牌解析出来。

实现了JWT令牌的生成,下面我们接着使用Java代码来校验JWT令牌(解析生成的令牌):

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

运行测试方法:

{id=1, exp=1672729730}

令牌解析后,我们可以看到id和过期时间,如果在解析的过程当中没有报错,就说明解析成功了。

最终编写成功JWT工具类(放在utils包下)

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;
    }
}

重写登录模块如下:

@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("用户名或密码错误");
    }
}

JWT令牌怎么返回给前端呢?此时我们就需要再来看一下接口文档当中关于登录接口的描述(主要看响应数据):

  • 响应数据

    参数格式:application/json

    参数说明:

    名称类型是否必须默认值备注其他信息
    codenumber必须响应码, 1 成功 ; 0 失败
    msgstring非必须提示信息
    datastring必须返回的数据 , jwt令牌

    响应数据样例:

    {
      "code": 1,
      "msg": "success",
      "data": "eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoi6YeR5bq4IiwiaWQiOjEsInVzZXJuYW1lIjoiamlueW9uZyIsImV4cCI6MTY2MjIwNzA0OH0.KkUc_CXJZJ8Dd063eImx4H9Ojfrr6XMJ-yVzaWCVZCo"
    }
  • 备注说明

    用户登录成功后,系统会自动下发JWT令牌,然后在后续的每次请求中,都需要在请求头header中携带到服务端,请求头的名称为 token ,值为 登录时下发的JWT令牌。

    如果检测到用户未登录,则会返回如下固定错误信息:

    {
        "code": 0,
        "msg": "NOT_LOGIN",
        "data": null
    }

之后用户的每一个请求中都会带有token请求头,里面存放JWT字符串以供服务端校验。

 校验的操作需要结合统一拦截技术讲解,于是放在第四节。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

MyBatis 解决上篇的参数绑定问题以及XML方式交互

前言 上文:MyBatis 初识简单操作-CSDN博客 上篇文章我们谈到的Spring中如何使用注解对Mysql进行交互 但是我们发现我们返回出来的数据明显有问题 我们发现后面三个字段的信息明显没有展示出来 下面我们来谈谈解决方案 解决方案 这里的原因本质上是因为mysql中和对象中的字段属性…

基于粒子群算法的多目标搜索算法

粒子速度类似于梯度下降的方向 粒子群优化算法(Particle Swarm Optimization, PSO)的详细解读 - 知乎 (zhihu.com) 粒子群优化算法介绍 与多种群遗传算法有相似之处

未来购物新篇章:臻奶惠无人新零售

未来购物新篇章&#xff1a;臻奶惠无人新零售 随着科技的不断进步和消费者购物习惯的变化&#xff0c;无人新零售已经成为零售行业的一大趋势&#xff0c;它不仅重新定义了购物体验&#xff0c;也为零售行业带来了前所未有的变革。无人新零售&#xff0c;一种融合了AI技术、物…

保护Android应用安全:全面探究代码混淆在加固中的作用

Android APP 加固是优化 APK 安全性的一种方法&#xff0c;常见的加固方式有混淆代码、加壳、数据加密、动态加载等。下面介绍一下 Android APP 加固的具体实现方式。 混淆代码 使用 ipaguard工具可以对代码进行混淆&#xff0c;使得反编译出来的代码很难阅读和理解&#xff…

c++的STL(6)-- map和multimap

map和multimap概述 map和multimap中存储的是使用pair对象的键值对。 map和multimap底层也是使用红黑树的数据结构进行实现的。所以&#xff0c;map和multimap内部存储的键值对也是有序的。并且内部数据也是使用链表的形式进行关联。所以其的迭代器和指针&#xff0c;也只能进行…

淘宝商品详情用于选品上架,数据分析,代购商城建站,ERP系统商品数据选品,价格监控业务场景

大数据时代&#xff0c; 数据收集不仅是科学研究的基石&#xff0c; 更是企业决策的关键。 然而&#xff0c;如何高效地收集数据 成了摆在我们面前的一项重要任务。 本文将为你揭示&#xff0c; 一系列实时数据采集方法&#xff0c; 助你在信息洪流中&#xff0c; 找到…

分享一个宝藏课程:近屿AIGC工程师和产品经理训练营

说起AIGC&#xff0c;大家都会自然地想到近两年火的一塌糊涂的ChatGPT,而开发出它的OpenAI&#xff0c;去年年底的年化收入已突破16亿美元&#xff0c;部分OpenAI的管理层认为&#xff0c;按目前进度&#xff0c;到2024年底&#xff0c;OpenAI的年化收入至少能达到50亿美元。而…

hyper-v安装 windows10虚拟机后,登录一直是锁屏界面,无法开启增强会话

按键盘等&#xff0c;一直在锁屏界面&#xff0c;进不去&#xff0c;需要点击 上述图片按钮&#xff0c;切到 “基本会话”&#xff0c; 这样可以登录了&#xff1b; 切换到 ‘基本会话’ &#xff0c;登陆后&#xff0c; 打开 设置--登录选项--要求 Microsoft 账户使用Windo…

计算机网络面试问题(一)

1.在浏览器中输⼊URL并按下回⻋之后会发⽣什么 2.TCP三次握⼿的过程,为什么三次握手 TCP&#xff08;传输控制协议&#xff09;的三次握⼿是建⽴⽹络连接的过程&#xff0c;确保通信双⽅能够正确地进⾏数据传输。 第⼀次握⼿&#xff08;SYN&#xff09;&#xff1a; 客户端&am…

【笔记】通过码云Gitee获取OpenHarmony源码

Note&#xff1a;下面包含操作过程和问题解决&#xff08;首次安装Ubuntu&#xff0c;环境未完善&#xff09;&#xff0c;没有遇到问题可以直接跳过问题part了&#xff0c;小白也能完成配置下载。 前置准备&#xff08;Git环境账号&#xff09; &#xff08;一&#xff09;安…

Effective-C++阅读解析条款(条款二:尽量以const,enum,inline替换#define)

个人主页&#xff1a;Lei宝啊 愿所有美好如期而遇 书中说这个条款或许改为“宁可以编译器替换预处理器”比较好&#xff0c;这句话在我看来原因是这样的&#xff1a; 如果我们有这样一个宏(假设写这个宏的人比较粗心)&#xff1a;#define Add(x, y) x y 我们本意是想得到…

“创新强基·应用强链”2024第104届上海电子展会

2024第104届上海电子展会 2024 Shanghai electron Expo 时间:2024年11月18--20日 地点:上海新国际博览中心 主题:创新强基应用强链 上海与长三角各地产业协同发展&#xff0c;到2025年&#xff0c;初步建成具有全球影响力和竞争力的世界级电子信息产业集群。产业链稳定性和韧…

黄金票据制作

1、黄金票据 黄金票据在内网渗透中主要用于权限维持&#xff0c;即留下后门。使用黄金票据前提是你已经控制了整个域的域控制器。其核心原理与服务器中的krbtgt用户相关。从以下可以了解krbtgt原理&#xff1a; 前言 | windows protocolhttps://daiker.gitbook.io/windows-pro…

DNDC模型对所有处理的土壤温度和湿度模拟效果良好,但有时土壤湿度模拟存在偏差

使用 DNDC 模型评估加拿大多样化作物轮作系统对产量和 N2O 排放的影响 原名&#xff1a;Assessing the impacts of diversified crop rotation systems on yields and nitrous oxide emissions in Canada using the DNDC model 译名&#xff1a;使用 DNDC 模型评估加拿大多样…

使用vite创建一个react18项目

一、vite是什么&#xff1f; vite 是一种新型前端构建工具&#xff0c;能够显著提升前端开发体验。它主要由两部分组成&#xff1a; 一个开发服务器&#xff0c;它基于原生 ES 模块提供了丰富的内建功能&#xff0c;如速度快到惊人的模块热更新&#xff08;HMR&#xff09;。 …

站群CMS系统

站群CMS系统是一种用于批量建立和管理网站的内容管理系统&#xff0c;它能够帮助用户快速创建大量的网站&#xff0c;并实现对这些网站的集中管理。以下是三个在使用广泛的站群CMS系统&#xff0c;它们各具特色&#xff0c;可以满足不同用户的需求。 1. Z-BlogPHP Z-BlogPHP是…

PSA制氧设备装置的使用注意事项解析

PSA制氧设备&#xff0c;即变压吸附制氧设备&#xff0c;是一种利用物理吸附原理&#xff0c;通过特定的吸附剂&#xff0c;在压力变化的情况下&#xff0c;从空气中分离出氧气的设备。由于其高效、节能、环保等特点&#xff0c;PSA制氧设备在工业、能源等领域得到了广泛应用。…

QCustomPlot一、QCustomPlot基础及画图显示

1、QCustomPlot下载 QCustomPlot源码demo 根据需要选择需要的文件&#xff1a; 完整版。QCustomPlot.tar.gz 源代码例子帮助文档&#xff1b; 共享库。QCustomPlot-sharedlib.tar.gz 库编译和使用&#xff1b; 源代码。QCustomPlot-source.tar.gz 源代码 里面包含了很多QCusto…

JavaEE 初阶篇-深入了解单例模式(经典单例模式:饿汉模式、懒汉模式)

&#x1f525;博客主页&#xff1a; 【小扳_-CSDN博客】 ❤感谢大家点赞&#x1f44d;收藏⭐评论✍ 文章目录 1.0 单例模式的概述 2.0 单例模式 - 饿汉式单例 2.1 关于饿汉式单例的线程安全问题 3.0 单例模式 - 懒汉式单例 3.1 关于懒汉式单例的线程安全问题 3.1.1 加锁 synchr…

设计模式——行为型——责任链模式Chain Of Responsibility

请求类 public class ApproverRequest {private int type;//请求批准的类型private float price;//请求的金额private int id;//请求的编号 } 审批人抽象类 public abstract class ApproverPerson {protected ApproverPerson next;protected String name;//审批过程public a…