【第3章】SpringBoot实战篇之登录接口(含JWT和拦截器)
文章目录
- 前言
- 一、JWT
- 1. 什么是JWT
- 2. 使用场景
- 3. 结构
- 3.1 Header
- 3.2 Payload
- 3.3 Signature
- 4. 使用
- 二、案例
- 1.引入库
- 2.JwtUtils
- 3. UserController1
- 4. ArticleController
- 三、拦截器
- 1. 定义拦截器
- 2. 注册拦截器
- 四、测试
- 1. 登录
- 2. 无token
- 3. 有token
- 4. 全局配置
- 总结
前言
前面已经完成了用户注册,这里我们基于之前的用户表,完成用户的登录接口。
一、JWT
1. 什么是JWT
JWT全称JSON Web Token,JSON Web令牌(JWT)是一种开放标准(RFC 7519),它定义了一种紧凑且自包含的方式,用于作为JSON对象在各方之间安全地传输信息。此信息是经过数字签名的,因此可以验证和信任。JWT可以使用秘密(使用HMAC算法)或使用RSA或ECDSA的公钥/私钥对进行签名。
虽然JWT可以加密,也可以在各方之间提供保密性,但我们将专注于签名代币。签名令牌可以验证其中包含的声明的完整性,而加密令牌则向其他方隐藏这些声明。当使用公钥/私钥对对令牌进行签名时,签名还证明只有持有私钥的一方才是签名方。
2. 使用场景
以下是JSON Web令牌有用的一些场景:
授权:这是使用JWT最常见的场景。一旦用户登录,每个后续请求都将包括JWT,允许用户访问该令牌允许的路由、服务和资源。单点登录是目前广泛使用JWT的一个功能,因为它的开销很小,并且能够在不同的域中轻松使用。
信息交换:JSON Web令牌是在各方之间安全传输信息的好方法。因为JWT可以签名——例如,使用公钥/私钥对——所以你可以确保发送者就是他们所说的那个人。此外,由于签名是使用标头和有效载荷计算的,因此还可以验证内容是否未被篡改。
3. 结构
以
.
作为各部分分隔符
xxxxx.yyyyy.zzzzz
- Header
- Payload
- Signature
3.1 Header
算法可以使用 HMAC SHA256 or RSA
{"alg": "HS256","typ": "JWT"
}
java-jwt 支持以下签名和验证算法:
JWS | Algorithm | Description |
---|---|---|
HS256 | HMAC256 | HMAC with SHA-256 |
HS384 | HMAC384 | HMAC with SHA-384 |
HS512 | HMAC512 | HMAC with SHA-512 |
RS256 | RSA256 | RSASSA-PKCS1-v1_5 with SHA-256 |
RS384 | RSA384 | RSASSA-PKCS1-v1_5 with SHA-384 |
RS512 | RSA512 | RSASSA-PKCS1-v1_5 with SHA-512 |
ES256 | ECDSA256 | ECDSA with curve P-256 and SHA-256 |
ES384 | ECDSA384 | ECDSA with curve P-384 and SHA-384 |
ES512 | ECDSA512 | ECDSA with curve P-521 and SHA-512 |
3.2 Payload
有效载荷用来存放一些用户信息,但不建议存放用户私密信息,以免造成不必要的安全隐患。
{"sub": "1234567890","name": "John Doe","admin": true
}
3.3 Signature
签名用于验证消息在发送过程中没有更改,并且,在使用私钥签名的令牌的情况下,它还可以验证JWT的发送者是它所说的那个人。
HMACSHA256(base64UrlEncode(header) + "." +base64UrlEncode(payload),secret)
4. 使用
在身份验证中,当用户使用其凭据成功登录时,将返回一个JSON Web令牌。由于令牌是凭据,因此必须非常小心地防止出现安全问题。一般来说,您不应将令牌保存的时间超过所需的时间。
每当用户想要访问受保护的路由或资源时,用户代理都应该发送JWT,通常在Authorization头中使用Bearer模式。标头的内容应如下所示:
Authorization: Bearer <token>
请注意,如果您通过HTTP头发送JWT令牌,则应尽量防止它们变大。有些服务器不接受超过8 KB的标头。如果您试图在JWT令牌中嵌入太多信息,例如通过包括所有用户的权限,您可能需要一个替代解决方案,如Auth0细粒度授权。
如果令牌是在Authorization标头中发送的,则跨来源资源共享(CORS)不会成为问题,因为它不使用cookie。
下图显示了如何获取JWT并将其用于访问API或资源:
二、案例
1.引入库
<dependency><groupId>com.auth0</groupId><artifactId>java-jwt</artifactId><version>4.4.0</version>
</dependency>
2.JwtUtils
package org.example.springboot3.bigevent.utils;import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.DecodedJWT;
import java.util.Date;
import java.util.Map;public class JwtUtils {private static final String SECRET = "167589447321";/*** 生成token* @param claims 用户信息* @return String*/public static String create(Map<String, Object> claims) {return JWT.create().withClaim("claims", claims).withIssuer("auth0").withExpiresAt(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 24)).sign(Algorithm.HMAC256(SECRET));}/*** 验证token* @param token token* @return boolean*/public static boolean verify(String token) {DecodedJWT decodedJWT;try {Algorithm algorithm = Algorithm.HMAC256(SECRET);JWTVerifier verifier = JWT.require(algorithm)// specify any specific claim validations.withIssuer("auth0")// reusable verifier instance.build();decodedJWT = verifier.verify(token);} catch (JWTVerificationException exception){// Invalid signature/claimsreturn false;}return true;}/*** 解析token数据* @param token token* @return Map*/public static Map<String, Object> getClaims(String token) {return JWT.require(Algorithm.HMAC256(SECRET)).withIssuer("auth0").build().verify(token).getClaim("claims").asMap();}}
3. UserController1
package org.example.springboot3.bigevent.controller;import jakarta.validation.Valid;
import jakarta.validation.constraints.Pattern;
import org.example.springboot3.bigevent.entity.Result;
import org.example.springboot3.bigevent.entity.User;
import org.example.springboot3.bigevent.service.UserSerivce;
import org.example.springboot3.bigevent.utils.JwtUtils;
import org.example.springboot3.bigevent.utils.Md5Util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;/*** Create by zjg on 2024/5/22*/
@RequestMapping("/user/")
@RestController
@Validated
public class UserController1 {@AutowiredUserSerivce userSerivce;@RequestMapping("register")public Result register(@Pattern(regexp = "^\\S{6,20}$",message = "用户名长度为6-20位") String username,@Pattern(regexp = "^\\S{8,20}$",message = "密码为8-20位") String password){User user=userSerivce.findUserByName(username);if(user==null){//用户不存在,可以注册int i=userSerivce.addUser(username,password);if(i!=1){return Result.error("失败注册,请稍后重新注册!");}}else{return Result.error("该用户已存在,请重新注册!");}return Result.success();}@RequestMapping("register1")public Result register1(@Valid User user){if(userSerivce.findUserByName(user.getUsername())==null){//用户不存在,可以注册int i=userSerivce.addUser(user.getUsername(),user.getPassword());if(i!=1){return Result.error("失败注册,请稍后重新注册!");}}else{return Result.error("该用户已存在,请重新注册!");}return Result.success();}@RequestMapping("login")public Result login(@Valid User loginUser){String message="用户名/密码不正确";User user = userSerivce.findUserByName(loginUser.getUsername());if(user!=null){//用户存在if(user.getPassword().equals(Md5Util.getMD5String(loginUser.getPassword()))){//密码正确Map<String,Object> claims=new HashMap();claims.put("userId",user.getId());claims.put("username",user.getUsername());String token = JwtUtils.create(claims);return Result.success("登录成功",token);}}return Result.error(message);}//todo 登出暂未使用@RequestMapping("logout")public Result logout(@Valid User loginUser){String message="用户名/密码不正确";User user = userSerivce.findUserByName(loginUser.getUsername());if(user!=null){//用户存在if(user.getPassword().equals(Md5Util.getMD5String(loginUser.getPassword()))){//密码正确Map<String,Object> claims=new HashMap();claims.put("userId",user.getId());claims.put("userUsername",user.getUsername());String token = JwtUtils.create(claims);return Result.success(token);}}return Result.error(message);}
}
4. ArticleController
主要为测试使用
package org.example.springboot3.bigevent.controller;import org.example.springboot3.bigevent.entity.Result;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;/*** Create by zjg on 2024/5/26*/
@RestController
@RequestMapping("/article/")
public class ArticleController {@RequestMapping("list")public Result<String> list(){return Result.success("article.list");}
}
三、拦截器
1. 定义拦截器
我们使用拦截器来对接口进行横切面的token验证
package org.example.springboot3.bigevent.inceptors;import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectReader;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.example.springboot3.bigevent.entity.Result;
import org.example.springboot3.bigevent.utils.JwtUtils;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;/*** Create by zjg on 2024/5/26*/
@Component
public class LoginInceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {String token = request.getHeader("Authorization");if(token!=null&&token.contains("Bearer")){boolean verify = JwtUtils.verify(token.substring(token.indexOf("Bearer")+7));if(verify){return true;}}response.setStatus(HttpStatus.UNAUTHORIZED.value());response.setContentType("application/json;charset=UTF-8");ObjectMapper objectMapper = new ObjectMapper();objectMapper.writerFor(Result.class);String message = objectMapper.writeValueAsString(Result.error("token验证失败,请重新获取token后重试!"));response.getWriter().println(message);return false;}
}
2. 注册拦截器
拦截器拦截初注册和登录之外的所有请求
package org.example.springboot3.config;import org.example.springboot3.bigevent.inceptors.LoginInceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.ArrayList;
import java.util.List;/*** Create by zjg on 2024/5/26*/
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {@AutowiredLoginInceptor loginInceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {List<String> patterns=new ArrayList<>();patterns.add("/user/register");patterns.add("/user/login");registry.addInterceptor(loginInceptor).excludePathPatterns(patterns);}
}
四、测试
1. 登录
2. 无token
3. 有token
4. 全局配置
在Postman中可以对目录配置token认证信息,对目录下的全部接口生效。
总结
回到顶部
JWT官网
JWT快速入门
相关文章:

【第3章】SpringBoot实战篇之登录接口(含JWT和拦截器)
文章目录 前言一、JWT1. 什么是JWT2. 使用场景3. 结构3.1 Header3.2 Payload3.3 Signature 4. 使用 二、案例1.引入库2.JwtUtils3. UserController14. ArticleController 三、拦截器1. 定义拦截器2. 注册拦截器 四、测试1. 登录2. 无token3. 有token4. 全局配置 总结 前言 前面…...

vue el-table使用、el-popover关闭、el-image大图预览
1、html <el-table :data"list" :header-cell-style"{ background: #F7F8F9 }"><el-table-column type"index" width"100px" label"序号"></el-table-column><el-table-column prop"pic" l…...

星网智云总经理韦炜:低代码与智能制造融合,探索未来制造的无限可能
下文为广西星网智云总经理韦炜的演讲全文: 大家下午好,今天给大家分享一下玉柴的数字化转型过程,以及整个过程中我们会怎样使用低代码。 ﹀ ﹀ ﹀ #玉柴数字化战略 #两个要点 我们的数字化,是在公司的整一个战略转型下去做的。…...

3d模型批量渲图总是会跳怎么办?---模大狮模型网
在进行3D模型批量渲染时,有时会遇到一些问题,其中一个常见的问题就是渲染过程中出现跳帧或者跳图的情况。这不仅会影响到效率,还可能导致输出结果不符合预期。本文将介绍几种解决这一问题的方法,帮助读者更好地应对3D模型批量渲图…...

【距离四六级只剩一个星期!】刘晓艳四级保命班课程笔记(2)(可分享治资料~)
这一节是专门的听力课程,众所周知,咱们刘晓艳刘老师的口语不是特别的突出,当然口才是一流的☝️。 文章目录 听力预判听前预判 听力过程八大出题关键点视听一致同义转换 听完一道题后平时练习精听步骤 听力预判 听前预判 画关键词ÿ…...

Java之Enum枚举类实践
概述 项目中涉及到很多不变的业务变量,因此我们采用了Enum类来定义相关变量,采用Enum的原因 性能高,常量值的地址唯一,可以直接使用 来判断 完全单例,线程安全 项目实践 package com.bierce;/*** 审核流传状态枚举类*/ public enum FlowTypeEnum {START("开始"…...

Apache POI对Excel进行读写操作
1、什么是Apache POI Apache POI 是一个处理Miscrosoft Office各种文件格式的开源项目。简单来说就是,我们可以使用 POI 在 Java 程序中对Miscrosoft Office各种文件进行读写操作。一般情况下,POI 都是用于操作 Excel 文件。 Apache POI 的应用场景&…...

网络安全中攻击溯源方法
目前网络攻击已经成为常见的安全威胁之一,其造成的危害和损失都是不可估量的,因此网络攻击受到了高度重视。而当我们遭遇网络攻击时,攻击溯源是一项非常重要的工作,可以帮助我们迅速发现并应对各类网络攻击行为,那么网…...

软件设计不是CRUD(21):在流式数据处理系统中进行业务抽象落地——需求分析
本文主要介绍如何在数据处理系统中应用业务抽象的设计思想。目前业界流行的数据处理方式是流式处理,主流的流式处理引擎有Apache Spark,Apache Flink等等。本文选择Apache Flink作为实战案例的落地。由于本文主要是讲解设计思想和流式处理引擎相结合的方…...

远控免杀篇
0x00:前言 随着近两年hvv和红蓝对抗以及国家对于网络安全的重视,国内防护水平都蹭蹭上了一个台阶,不管是内部人员的技术水平提高还是防护设备的层层部署,均给了红队人员想要进一步行动设置了障碍。 通过weblogic的cve-2019-2725获…...

基于单片机的超声波倒车雷达设计
摘 要:文 章设计了一种基于单片机的超声波倒车雷达系统,以 AT89C51 型单片机作为控制核心,集距离测量、显示,方位显示和危险报警于一体,以提高驾驶者在倒车泊车时的安全性和舒适性。本设计采用 Keil 软件对系统程序…...

如何增加服务器的高并发
哈喽呀大家好呀,淼淼又来和大家见面啦,随着互联网应用的普及和用户量的不断增加,服务器的高并发性能成为了开发者们面临的一项重要挑战。在处理大量并发请求时,服务器需要具备高效的处理能力和稳定的性能,以确保系统的…...

webservice、WCF、webAPI权限认证
webservice 权限认证 》》soapHeader SOAPHeader案例 》》 window 集成认证 在IIS里取消匿名访问权限,若允许匿名访问,就没有必须提供验证凭证了 R2RServiceSerialNumber sN new R2RServiceSerialNumber();sN.Url "http://172.xxxxx/R2RServi…...

Kafka之Producer原理
1. 生产者发送消息源码分析 public class SimpleProducer {public static void main(String[] args) {Properties prosnew Properties();pros.put("bootstrap.servers","192.168.8.144:9092,192.168.8.145:9092,192.168.8.146:9092"); // pros.pu…...

ubuntu20.04部署gitlab流程
参考: https://blog.csdn.net/weixin_57025326/article/details/136048507 362 wget --content-disposition https://packages.gitlab.com/gitlab/gitlab-ce/packages/ubuntu/focal/gitlab-ce_16.2.1-ce.0_amd64.deb/download.deb367 sudo apt install gitlab-ce…...

C/C++动态内存管理(new与delete)
目录 1. 一图搞懂C/C的内存分布 2. 存在动态内存分配的原因 3. C语言中的动态内存管理方式 4. C内存管理方式 4.1 new/delete操作内置类型 4.2 new/delete操作自定义类型 1. 一图搞懂C/C的内存分布 说明: 1. 栈区(stack):在…...

搭建一个基于主流技术Spring Boot 2 + Vue 3 + Ant Design Vue的技术框架的简要步骤
搭建一个基于主流技术Spring Boot 2 Vue 3 Ant Design Vue的技术框架涉及前后端分离的开发模式。以下是一个简化的步骤指南,用于帮助你开始这个项目: 1. 后端(Spring Boot 2) 1.1 初始化项目 使用Spring Initializr(…...

水电站生产指挥调度系统方案
一、方案背景 在碧波荡漾的大江大河之上,巍然屹立着一座座水电站,它们如同一个个巨人在默默地守护着我们的家园。在这些建设者的辛勤耕耘下,水电站在保障国家能源安全、优化能源结构以及减少环境污染等方面发挥着重要作用。 然而,…...

深度学习入门-第3章-神经网络
前面的待补充 3.6 手写数字识别 3.6.1 MNIST 数据集 本书提供了便利的 Python 脚本 mnist.py ,该脚本支持从下载 MNIST 数据集到将这些数据转换成 NumPy 数组等处理(mnist.py 在 dataset 目录下)。 使用 mnist.py 时,当前目录必须…...

如何使用AES128位进行视频解密
要实现AES128位加解密,可以使用JavaScript的crypto-js库。以下是一个简单的示例: HTML代码: <video controlsList"nodownload" controls></video> 首先,需要安装crypto-js库: npm install cr…...

ArkTS是前端语言吗
ArkTS是前端语言吗 ArkTS,这个名词在现代软件开发领域里逐渐崭露头角,但对于许多人来说,它仍旧是个神秘而令人困惑的存在。那么,ArkTS究竟是前端语言吗?为了回答这个问题,我们需要从多个方面进行深入剖析。…...

git上新down下来的项目,前端启动报错npm ERR! code 1 npm ERR! path E:\code\vuehr\node_modul
解决方法在下面 问题1:> vuehr0.1.0 serve > vue-cli-service serve vue-cli-service 不是内部或外部命令,也不是可运行的程序 或批处理文件。 在项目目录下执行命令npm i -D vue/cli-service来安装vue/cli-service依赖。 运行gitee上下载的…...

oc中的数据结构在都在什么位置
数据结构 在Objective-C中,数据结构可以存在于以下几个位置: 堆(Heap):堆是动态分配的内存空间,用于存储动态创建的对象和数据结构。堆上的数据需要手动进行内存管理,即手动分配和释放内存。 …...

多云世界中的 API 治理
随着企业不断拥抱数字化转型,许多企业正在采用多云战略,以充分利用不同云平台的独特优势和功能。这种方法使企业能够避免被供应商锁定,提高灵活性,并优化 IT 成本。然而,在多个云平台上管理应用程序接口并非易事。它带…...

【稳定检索/投稿优惠】2024年环境、资源与区域经济发展国际会议(ERRED 2024)
2024 International Conference on Environment, Resources and Regional Economic Development 2024年环境、资源与区域经济发展国际会议 【会议信息】 会议简称:ERRED 2024 大会地点:中国杭州 会议官网:www.icerred.com 会议邮箱࿱…...

生成式 AI——ChatGPT、Dall-E、Midjourney 等算法理念探讨
1.概述 艺术、交流以及我们对现实世界的认知正在迅速地转变。如果我们回顾人类创新的历史,我们可能会认为轮子的发明或电的发现是巨大的飞跃。今天,一场新的革命正在发生——弥合人类创造力和机器计算之间的鸿沟。这正是生成式人工智能。 生成模型正在模…...

C-数据结构-树状存储基本概念
‘’’ 树状存储基本概念 深度(层数) 度(子树个数) 叶子 孩子 兄弟 堂兄弟 二叉树: 满二叉树: 完全二叉树: 存储:顺序,链式 树的遍历:按层遍历࿰…...

【Linux-Yocto】
Linux-Yocto ■ 1.1 安装 Git 与配置 Git 用户信息■ 1.2 获取 Yocto 项目■ 1.3 开始构建 Yocto 文件系统■ 1.4 构建 SDK 工具■■■ ■ 1.1 安装 Git 与配置 Git 用户信息 sudo apt-get install git git config --global user.name "username" // 配置 Git 用户名…...

一文掌握JavaScript 中类的用法
文章导读:AI 辅助学习前端,包含入门、进阶、高级部分前端系列内容,当前是 JavaScript 的部分,瑶琴会持续更新,适合零基础的朋友,已有前端工作经验的可以不看,也可以当作基础知识回顾。 这篇文章…...

国密算法:信息安全的守护者
在数字化时代,信息安全已成为国家安全的重要组成部分。国密算法,作为中国自主研发的一套密码算法体系,对于提升国家信息安全水平、保障关键信息基础设施的安全具有重要意义。本文将详细介绍国密算法的组成、特点以及在信息安全领域的应用。 国…...