初识Jwt(结合SpringBoot)

最近接触JWT,顺便记录下

目录

  • JWT简介
  • JWT组成
  • JWT使用流程
  • JWT实战
    • 引入Maven
    • 核心代码
  • JWT优缺点

JWT简介

JWT是JSON Web Token的简称,是目前流行的跨域的认证解决方案,作为传递信息的凭证,它是由服务器端签发的且是带签名的,服务器端通过数字签名来保证数据的完整性和有效性。

JWT组成

Jwt由三部分组成: Header(头部)、Payload(负载)、Signature(签名)
这里简单讲解下吧,其实已经很多博主都讲了的,我这边就…照搬~
头部(Header):JWT 的头部通常由两部分信息组成:令牌的类型(即JWT)和所使用的签名算法,例如:{ “alg”: “HS256”, “typ”: “JWT”}
载荷(Payload):JWT的载荷包含了一些声明(Claim),用于描述用户信息、权限、过期时间等等,例如:{ “name”: “zhang”, “userid”: “123”}
签名(Signature):JWT的签名由头部和载荷组成,并使用密钥进行加密生成

JWT使用流程

基于系统登陆:用户使用用户名和密码进行登录,服务器验证用户信息是否正确。
1、服务器通过JWT生成token,将用户信息、权限等信息写入载荷中,并使用密钥对头部和载荷进行签名。
2、服务器将生成的token返回给客户端,客户端将其存储在本地,通常是在浏览器的cookie或本地存储中。
3、客户端在后续的请求中,将token作为请求头部或请求参数传递给服务器。
4、服务器收到请求后,验证token的签名是否正确,如果正确则解析出用户信息、权限等信息,进行后续操作。

基于对接验证:第三方对外接口时可使用JWT生成的token作为验证凭证(有时间限制)
1、请求第三方服务器,将第三方授权信息等信息写入载荷中,并使用第三方提供的密钥对头部和载荷进行签名。
2、第三方将生成的token返回给请求方,请求方将token存储至数据库或缓存,可设置自动失效或失效后自动获取token
3、请求方在后续的请求接口中,将token作为请求头部或请求参数传递给第三方。
4、第三方收到请求后,验证token的签名是否正确,如果正确则解析出授权信息进行验证,若无误再进行后续操作

JWT实战

引入Maven

<dependency>
    <groupId>com.auth0</groupId>
    <artifactId>java-jwt</artifactId>
    <version>3.10.3</version>
</dependency>

核心代码

Jwt工具类

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import java.util.Calendar;
import java.util.Map;

public class JwtUtils {
    //密钥(自定义)
    private static String secret = "JwtTest";
    //过期时间(分钟)
    private static int expireMinutes = 10;

    //创建Token
    public static String getToken(Map<String,String> map){

        Calendar instance = Calendar.getInstance();
        //获取具体失效时间
        instance.add(Calendar.SECOND,60 * expireMinutes);

        JWTCreator.Builder builder = JWT.create();
        map.forEach((k,v)->{
            builder.withClaim(k,v);
        });
        //设置过期时间
        builder.withExpiresAt(instance.getTime());

        return builder.sign(Algorithm.HMAC256(secret));
    }

    //验证Token
    public static void isVerify(String token){
        DecodedJWT jwt = JWT.require(Algorithm.HMAC256(secret)).build().verify(token);
    }
}

拦截器(实现登录后验证获取信息)

import com.auth0.jwt.exceptions.AlgorithmMismatchException;
import com.auth0.jwt.exceptions.SignatureVerificationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.zhangximing.springboot_jwt.util.JwtUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;

/**
 * JWT拦截器
 */
public class JWTInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        HashMap<String, Object> map = new HashMap<>();
        System.out.println("JWT拦截器拦截到请求");
        //获取请求头中的token
        String token = request.getHeader("token");
        try {
            //验证令牌
            JwtUtils.isVerify(token);
            //放行请求
            return true;
        }catch (SignatureVerificationException e) {
            e.printStackTrace();
            map.put("msg","无效签名");
        }catch (TokenExpiredException e){
            e.printStackTrace();
            map.put("msg","token过期");
        } catch (AlgorithmMismatchException e) {
            e.printStackTrace();
            map.put("msg","算法不一致");
        }catch (Exception e){
            e.printStackTrace();
            map.put("msg","token无效");
        }
        map.put("state",false);

        // 将map转为json,响应给前端
        String json = new ObjectMapper().writeValueAsString(map);
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().println(json);
        return HandlerInterceptor.super.preHandle(request, response, handler);
    }
}
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * 拦截器配置
 */
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new JWTInterceptor())
                .addPathPatterns("/**")
                //除登陆方法外其他路径都拦截
                .excludePathPatterns("/user/login");
    }

    /**
     * 如果实现了Filter跨域拦截,这个跨域无效
     * 拦截器实现 跨域支持
     * @param registry
     */
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOriginPatterns("*")  //本人测试时springboot2.7版本用的是这个
                .allowCredentials(true)
                .allowedMethods("GET", "POST", "DELETE", "PUT","OPTIONS","HEAD")
                .allowedHeaders("*")
                .maxAge(3600);
    }
}

测试方法

import com.zhangximing.springboot_jwt.util.JwtUtils;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;

@RestController
@RequestMapping("/user")
public class UserController {

    //测试验证
    @RequestMapping("/test")
    public Map<String,Object> test(){
        HashMap<String, Object> map = new HashMap<>();
        map.put("state",true);
        map.put("msg","请求成功");

        return map;
    }

    //用户登录,认证token
    @RequestMapping("/login")
    public Map<String,Object> login(@RequestBody Map<String,Object> paramMap){
        HashMap<String, Object> map = new HashMap<>();
        try {
            //模拟登陆
            Map<String, String> loginInfo = MyLogin((String) paramMap.get("userName"), (String) paramMap.get("password"));

            //登陆成功后,返回token
            Map<String,String> payload = new HashMap<>();
            payload.put("userId",loginInfo.get("userId"));
            payload.put("userName",loginInfo.get("userName"));
            //生成JWT令牌
            String token = JwtUtils.getToken(payload);
            //token返回
            map.put("state",true);
            map.put("msg","认证成功");
            map.put("token",token);
        } catch (Exception e) {
            map.put("state",false);
            map.put("msg",e.getMessage());
        }
        return map;
    }

    //模拟登陆
    public Map<String,String> MyLogin(String userName,String password){
        if ("zhangximing".equals(userName) && "123456".equals(password)){
            Map<String,String> map = new HashMap<>();
            map.put("userId","1");
            map.put("userName","zhangximing");

            return map;
        }else{
            throw new RuntimeException("用户名或密码错误");
        }
    }
}

测试结果(模拟登陆、正常登陆、登陆失效)

模拟登陆
正常登陆

登陆超时

JWT优缺点

引用一个博主的总结 https://blog.csdn.net/wingrant/article/details/126445880

JWT优点:
1、因为json的通用性,JWT是可以跨语言支持的,像JAVA,JavaScript,NodeJS,PHP等语言都能使用。
2、因为有了payload部分,所以JWT可以在自身存储一些其他业务逻辑所必要的非敏感信息。
3、便于传输。JWT的构成非常简单,字节占用很小,所以它是非常便于传输的。 它不需要在服务端保存会话信息, 所以它易于应用的扩展。

JWT缺点:
1、占带宽: 正常情况下要比 session_id 更大,需要消耗更多流量,挤占更多带宽,假如你的网站每月有 10万次的浏览器,就意味着要多开销几十兆的流量。听起来并不多,但日积月累也是不小一笔开销。实际上,许多人会在 JWT 中存储的信息会更多。
2、无法在服务端注销。用户主动注销时一般会让前端清理token,后端不理会,很难解决劫持问题。其他解决办法都是有状态的,例如通过Redis存储token副本、Redis存储token版本号、Redis存储过期时间等。
3、性能问题: JWT 的卖点之一就是加密签名,由于这个特性,接收方得以验证 JWT 是否有效且被信任。但是大多数 Web身份认证应用中,JWT 都会被存储到 Cookie中,这就是说你有了两个层面的签名。听着似乎很牛逼,但是没有任何优势,为此,你需要花费两倍的 CPU 开销来验证签名。对于有着严格性能要求的Web 应用,这并不理想,尤其对于单线程环境。

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

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

相关文章

Vue-Router学习笔记

文章目录 一、Vue Router简介二、简单使用三、动态路由匹配3.1 响应路由参数的变化3.2 捕获所有路由或 404 Not found 路由 四、路由的匹配语法4.1 在参数中自定义正则4.2 可重复的参数4.3 Sensitive 与 strict 路由配置4.4 可选参数 五、嵌套路由嵌套的命名路由 六、编程式导航…

CMAQ空气质量模式在移动源污染控制中的技术应用

CMAQ&#xff08;Community Multiscale Air Quality&#xff09;空气质量模式是一种先进的空气质量模拟工具&#xff0c;广泛应用于环境科学、气象学以及大气污染控制等领域。该模式能够综合考虑大气中各种污染物的传输、扩散、转化和沉降过程&#xff0c;从而实现对空气质量的…

部署MGR集群(OpenEuler版步骤详细可参考)

MGR集群理论知识&#xff1a; MGR具备以下几个特点&#xff1a; 基于shared-nothing模式&#xff0c;所有节点都有一份完整数据&#xff0c;发生故障时可以直接切换。 MGR提供了数据一致性保障&#xff0c;默认是最终一致性&#xff0c;可根据业务特征需要自行调整一致性级别…

[Prob] Definition 3.7.5 (Function of two r.v.s)

定义3.7.5&#xff08;两个随机变量的函数&#xff09;&#xff1a;给定一个样本空间 \( S \) 的实验&#xff0c;如果 \( X \) 和 \( Y \) 是映射 到X(s) 和 Y(s) 的随机变量&#xff0c;那么 g(X, Y) 就是映射 s 到 g(X(s), Y(s)) 的随机变量。 请注意&#xff0c;我…

IEEE802.11v协议介绍

IEEE802.11v协议简介 协议全称&#xff1a;无线网络管理(Wireless Network Management) 批准日期&#xff1a;2011年2月 协议状态&#xff1a;并入802.11-2012 协议别名&#xff1a;BSS过渡管理 主要功能 支持AP和STA间交换&#xff1a;关于RF环境和拓扑状态的信息&#…

C#,精巧实用的代码,文件夹的时间整理工具FolderTime及其源代码

一、文件夹LastWriteTime 我们在Windows资源管理器中看到的文件夹时间,是什么时间呢? 按微软的解释,应该是该文件夹的最后写入(修改)的时间,称为 LastWriteTime。 DirectoryInfo root = new DirectoryInfo(@"c\root");DateTime ft = root.LastWriteTime; La…

C语言 ##程序填空题## 总结

以下仅个人总结。 1&#xff0c;下面程序的功能是计算1-35-7.....-99101的值&#xff0c;填空。 void main() {int i,t, s 0, sign 1;for (i 1; i < 101; i 2) {t i * sign;s t;sign -sign;}printf("%d", s); } 2&#xff0c;下面程序的功能是输出一个整…

Vue2利用创建a标签实现下载本地静态文件到本地电脑上的功能

最近PC项目遇到一个需求&#xff0c;那就是需要前端下载前端代码包里的前端文件到本地&#xff0c;并且可以给下载下来的文件名指定任意的文件名&#xff0c;如下图所示&#xff0c;在前端代码里public里的statics里有个静态文件zswj.pem&#xff0c;页面上有个下载按钮&#x…

短剧APP搭建,短剧时代下的收益方向

近年来&#xff0c;节奏快、剧情爽的短剧瞬间爆火&#xff0c;吸引了无数的观众&#xff0c;这也使得众多短剧制作商赚的盆满钵满&#xff0c;预计再过几年短剧市场规模将达到千亿元&#xff01;短剧市场的发展将不可估量。 随着各类短剧的出现&#xff0c;观众也急需观看短剧…

音视频开发_视频基础知识

RGB彩色原理 RGB 是表示红色 (Red)、绿色 (Green) 和蓝色 (Blue) 三种颜色的色彩模式&#xff0c;这是一种加色法。在 RGB 色彩模式中&#xff0c;通过不同比例的红、绿、蓝三原色的混合可以得到各种不同颜色。这是因为人眼对红、绿、蓝三种颜色特别敏感&#xff0c;通过它们的…

ArcGIS学习(十五)用地适宜性评价

ArcGIS学习(十五)用地适宜性评价 本任务给大家带来的内容是用地适宜性评价。 用地适宜性评价是大家在平时工作中最常接触到的分析场景之一。尤其是在国土空间规划的大背景下,用地适宜性评价变得越来越重要。 此外,我们之前的任务主要是使用矢量数据进行分析。本案例是主讲…

传感器是什么?有哪些类型及应用

什么是传感器 传感器是一种用于检测、测量和感知某种特定物理量或环境参数的设备或器件。它们能够将所测量的物理量转换为可供处理和分析的电信号、数字信号或其他形式的输出信号。传感器在各种领域中都有广泛的应用&#xff0c;包括工业、医疗、环境监测、汽车、航空航天、农…

Go——下划线

"_"是特殊标识符&#xff0c;用来忽略结果。 1. 下划线在import中 在golang中&#xff0c;import的作用是导入其他package。 import下划线的作用&#xff1a;当导入一个包时&#xff0c;该包下的文件里所有init()函数都会被执行&#xff0c;然而&#xff0c;有些时候…

数组扩展方法(二)

以下将对Array.prototype上的方法进行整理&#xff0c;es5中数组遍历的方法在 数组扩展方法&#xff08;一&#xff09;可以查看 会改变原始数组 以下方法都在Array.prototype原型上 push 数组尾部插入元素shift 数组首部删除元素unshift 向数组首部添加元素pop 数组尾部删除…

深入探究:AVL树的平衡之道

文章目录 一、AVL树的原理AVL树的定义和特性平衡因子的概念 二、AVL树的自平衡策略a. 单旋&#xff08;single rotation&#xff09;1. 左单旋&#xff08;Left Rotation&#xff09;&#xff1a;2. 右单旋&#xff08;Right Rotation&#xff09;&#xff1a; b. 双旋&#xf…

双向数据绑定:Vue.js的魔法背后

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

【PHP+代码审计】PHP基础——流程控制

&#x1f36c; 博主介绍&#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 hacker-routing &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【应急响应】 【Java、PHP】 【VulnHub靶场复现】【面试分析】 &#x1f389;点赞➕评论➕收…

大规模自动化重构框架--OpenRewrite浅析

目录 1. OpenRewrite是什么&#xff1f;定位&#xff1f; 2. OpenWrite具体如何做&#xff1f; 3. 核心概念释义 3.1 Lossless Semantic Trees (LST) 无损语义树 3.2 访问器&#xff08;Visitors&#xff09; 3.3 配方&#xff08;Recipes&#xff09; 4. 参考链接 Open…

FPGA 按键控制串口发送

按键消抖 消抖时间一般为10ms&#xff0c;我使用的板子是ACX720&#xff0c;晶振为50MHZ&#xff0c;20ns为一周期。 状态机 模块设计 设计文件 timescale 1ns / 1ps // // Company: // Engineer: // // Create Date: 2023/01/11 12:18:36 // Design Name: // Module Name…

Linux应用 inotify监控文件变化

1、前言 inotify是Linux内核提供的一种文件系统监控机制&#xff0c;可以用来监视文件系统的变化&#xff0c;如文件创建、删除、修改、移动等。通过inotify&#xff0c;用户空间程序可以实时获取文件系统的变化事件&#xff0c;并做出相应的处理。 主要特点&#xff1a; 实…