当前位置: 首页 > news >正文

Spring Security 构建基于 JWT 的登录认证

一言以蔽之,JWT 可以携带非敏感信息,并具有不可篡改性。可以通过验证是否被篡改,以及读取信息内容,完成网络认证的三个问题:“你是谁”、“你有哪些权限”、“是不是冒充的”。  
为了安全,使用它需要采用 Https 协议,并且一定要小心防止用于加密的密钥泄露。

采用 JWT 的认证方式下,服务端并不存储用户状态信息,有效期内无法废弃,有效期到期后,需要重新创建一个新的来替换。 
所以它并不适合做长期状态保持,不适合需要用户踢下线的场景,不适合需要频繁修改用户信息的场景。因为要解决这些问题,总是需要额外查询数据库或者缓存,或者反复加密解密,强扭的瓜不甜,不如直接使用 Session。不过作为服务间的短时效切换,还是非常合适的,就比如 OAuth 之类的。

目标功能点

  • 通过填写用户名和密码登录。

    • 验证成功后, 服务端生成 JWT 认证 token, 并返回给客户端。
    • 验证失败后返回错误信息。
    • 客户端在每次请求中携带 JWT 来访问权限内的接口。
  • 每次请求验证 token 有效性和权限,在无有效 token 时抛出 401 未授权错误。
  • 当发现请求带着的 token 有效期快到了的时候,返回特定状态码,重新请求一个新 token。
  • 2.png

    ​​​​​​​Spring Security是Spring家族中的安全框架,可以用来做用户验证和权限管理等。Spring Security是一款重型框架,不过功能十分强大。一般来说,如果项目中需要进行权限管理,具有多个角色和多种权限,我们可以使用Spring Security。SpringSecurity 采用的是责任链的设计模式,是一堆过滤器链的组合,它有一条很长的过滤器链。

准备工作

引入 Maven 依赖

针对这个登录验证的实现,需要引入 Spring Security、jackson、java-jwt 三个包。

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-core</artifactId><version>2.12.1</version>
</dependency>
<dependency><groupId>com.auth0</groupId><artifactId>java-jwt</artifactId><version>3.12.1</version>
</dependency>

配置 DAO 数据层

要验证用户前,自然是先要创建用户实体对象,以及获取用户的服务类。不同的是,这两个类需要实现 Spring Security 的接口,以便将它们集成到验证框架中。

User

用户实体类需要实现 ”UserDetails“ 接口,这个接口要求实现 getUsernamegetPasswordgetAuthorities 三个方法,用以获取用户名、密码和权限。以及 isAccountNonExpired`isAccountNonLockedisCredentialsNonExpiredisEnabled 这四个判断是否是有效用户的方法,因为和验证无关,所以先都返回 true。这里图方便,用了 lombok

@Data
public class User implements UserDetails {private static final long serialVersionUID = 1L;private String username;private String password;private Collection<? extends GrantedAuthority> authorities;...
}

UserService

用户服务类需要实现 “UserDetailsService” 接口,这个接口非常简单,只需要实现 loadUserByUsername(String username) 这么一个方法。这里使用了 MyBatis 来连接数据库获取用户信息。

@Service
public class UserService implements UserDetailsService {@AutowiredUserMapper userMapper;@Override@Transactionalpublic User loadUserByUsername(String username) {return userMapper.getByUsername(username);}...
}

创建 JWT 工具类

这个工具类主要负责 token 的生成,验证,从中取值。

@Component
public class JwtTokenProvider {private static final long JWT_EXPIRATION = 5 * 60 * 1000L; // 五分钟过期public static final String TOKEN_PREFIX = "Bearer "; // token 的开头字符串private String jwtSecret = "XXX 密钥,打死也不能告诉别人";...
}

生成 JWT:从以通过验证的认证对象中,获取用户信息,然后用指定加密方式,以及过期时间生成 token。这里简单的只加了用户名这一个信息到 token 中:

public String generateToken(Authentication authentication) {User userPrincipal = (User) authentication.getPrincipal(); // 获取用户对象Date expireDate = new Date(System.currentTimeMillis() + JWT_EXPIRATION); // 设置过期时间try {Algorithm algorithm = Algorithm.HMAC256(jwtSecret); // 指定加密方式return JWT.create().withExpiresAt(expireDate).withClaim("username", userPrincipal.getUsername()) .sign(algorithm); // 签发 JWT} catch (JWTCreationException jwtCreationException) {return null;}
}

验证 JWT:指定和签发相同的加密方式,验证这个 token 是否是本服务器签发,是否篡改,或者已过期。

public boolean validateToken(String authToken) {try {Algorithm algorithm = Algorithm.HMAC256(jwtSecret); // 和签发保持一致JWTVerifier verifier = JWT.require(algorithm).build();verifier.verify(authToken);return true;} catch (JWTVerificationException jwtVerificationException) {return false;}
}

获取荷载信息:从 token 的荷载部分里解析用户名信息,这部分是 md5 编码的,属于公开信息。

public String getUsernameFromJWT(String authToken) {try {DecodedJWT jwt = JWT.decode(authToken);return jwt.getClaim("username").asString();} catch (JWTDecodeException jwtDecodeException) {return null;}
}

登录

登录部分需要创建三个文件:负责登录接口处理的拦截器,登陆成功或者失败的处理类。

LoginFilter

Spring Security 默认自带表单登录,负责处理这个登录验证过程的过滤器叫“UsernamePasswordAuthenticationFilter”,不过它只支持表单传值,这里用自定义的类继承它,使其能够支持 JSON 传值,负责登录验证接口。

这个拦截器只需要负责从请求中取值即可,验证工作 Spring Security 会帮我们处理好。

滑动验证页面

SpringBoot整合Spring Security + JWT实现用户认证-阿里云开发者社区 

相关文章:

Spring Security 构建基于 JWT 的登录认证

一言以蔽之&#xff0c;JWT 可以携带非敏感信息&#xff0c;并具有不可篡改性。可以通过验证是否被篡改&#xff0c;以及读取信息内容&#xff0c;完成网络认证的三个问题&#xff1a;“你是谁”、“你有哪些权限”、“是不是冒充的”。 为了安全&#xff0c;使用它需要采用 …...

PyTorch从零开始实现Transformer

文章目录 自注意力Transformer块编码器解码器块解码器整个Transformer参考来源全部代码&#xff08;可直接运行&#xff09; 自注意力 计算公式 代码实现 class SelfAttention(nn.Module):def __init__(self, embed_size, heads):super(SelfAttention, self).__init__()self.e…...

运动蓝牙耳机什么牌子的好用、最好用的运动蓝牙耳机推荐

音乐是运动的灵魂&#xff0c;而一款优秀的运动耳机则是让音乐与我们的身体完美融合的关键。今天&#xff0c;我推荐五款备受运动爱好者喜爱的耳机&#xff0c;它们以卓越的音质、舒适的佩戴和出色的稳定性能脱颖而出&#xff0c;助你在运动中创造最佳状态。 1、NANK南卡Runne…...

HTTP、HTTPS协议详解

文章目录 HTTP是什么报文结构请求头部响应头部 工作原理用户点击一个URL链接后&#xff0c;浏览器和web服务器会执行什么http的版本持久连接和非持久连接无状态与有状态Cookie和Sessionhttp方法&#xff1a;get和post的区别 状态码 HTTPS是什么ssl如何搞到证书nginx中的部署 加…...

【算法与数据结构】222、LeetCode完全二叉树的节点个数

文章目录 一、题目二、一般遍历解法三、利用完全二叉树性质四、完整代码 所有的LeetCode题解索引&#xff0c;可以看这篇文章——【算法和数据结构】LeetCode题解。 一、题目 二、一般遍历解法 思路分析&#xff1a;利用层序遍历&#xff0c;然后用num记录节点数量。其他的例如…...

登录和注册表单的11个HTML最佳实践

原文&#xff1a;11 HTML best practices for login & sign-up forms 原作者&#xff1a;Andrey Sitnik 翻译已获原文作者许可&#xff0c;禁止转载和商用 大多数网站都有登录或注册表单;它们是业务转换的关键部分。然而&#xff0c;即使是流行的站点也没有实现本文中提到的…...

Mysql删除历史数据

Mysql定时删除历史数据 实现 1.创建存储过程&#xff08;函数&#xff09; SQL DROP PROCEDURE IF EXISTS KeepDatasWith30Days CREATE PROCEDURE KeepDatasWith30Days() BEGINSELECT maxId:max(Id) FROM tableName WHERE CreateTime<DATE(DATE_SUB(NOW(),INTERVAL 31 D…...

Python—数据结构(一)

先放一张自己学习和整理归纳的思维导图&#xff0c;以便让大家都知道我自己的整体学习路线。 数据结构的学习路上内容枯燥&#xff0c;但坚持下来一定有很大的收获&#xff01;加油&#x1f4aa;&#x1f3fb;&#xff01; 数据结构 数据的概念数据元素&#xff1a; 若干基本…...

离线环境安装flask依赖包

找到当前版本需要的所有依赖包&#xff0c;生产flask项目生成项目依赖包文件requirements.txt 1)在当前项目目录下 生成requirements文件&#xff1a;pip freeze >requirements.txt 执行requirements文件&#xff0c;安装依赖包&#xff1a;pip install -r requirements.t…...

ChatGPT与Claude对比分析

一 简介 1、ChatGPT: 访问地址&#xff1a;https://chat.openai.com/ 由OpenAI研发,2022年11月发布。基于 transformer 结构的大规模语言模型,包含1750亿参数。训练数据集主要是网页文本,聚焦于流畅的对话交互。对话风格友好,回复通顺灵活,富有创造性。存在一定的安全性问题,可…...

登录和注册页面 - 验证码功能的实现

目录 1. 生成验证码 2. 将本地验证码发布成 URL 3. 后端返回验证码的 URL 给前端 4. 前端将用户输入的验证码传给后端 5. 后端验证验证码 1. 生成验证码 使用hutool 工具生成验证码. 1.1 添加 hutool 验证码依赖 <!-- 验证码 --> <dependency><groupId…...

HDFS的文件块大小(重点)

HDFS 中的文件在物理上是分块存储 &#xff08;Block &#xff09; &#xff0c; 块的大小可以通过配置参数( dfs.blocksize&#xff09;来规定&#xff0c;默认大小在Hadoop2.x/3.x版本中是128M&#xff0c;1.x版本中是64M。 如果一个文件文件小于128M&#xff0c;该文件会占…...

深度学习(二)

目录 一、神经网络 整体架构: 架构细节: 神经元个数的影响: 神经网络过拟合解决: 卷积网络 整体架构: 卷积层 边缘填充 特征尺寸计算 池化层 特征图变化 递归神经网络 一、神经网络 整体架构: 图中分别为输入层、隐层1、隐层2、输出层 通过输入层输入某数值&#xf…...

无涯教程-jQuery - wrapInner( html )方法函数

wrapInner(html)方法使用HTML结构包装每个匹配元素(包括文本节点)的内部子内容。 wrapInner( html ) - 语法 selector.wrapInner( html ) 这是此方法使用的所有参数的描述- html - 将动态创建并环绕目标的HTML字符串。 wrapInner( html ) - 示例 以下是一个简单的示例…...

【unity之IMGUI实践】单例模式管理数据存储【二】

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;uni…...

【C++】开源:Linux端ALSA音频处理库

&#x1f60f;★,:.☆(&#xffe3;▽&#xffe3;)/$:.★ &#x1f60f; 这篇文章主要介绍Linux端ALSA音频处理库。 无专精则不能成&#xff0c;无涉猎则不能通。。——梁启超 欢迎来到我的博客&#xff0c;一起学习&#xff0c;共同进步。 喜欢的朋友可以关注一下&#xff0c…...

【Linux | Shell】结构化命令2 - test命令、方括号测试条件、case命令

目录 一、概述二、test 命令2.1 test 命令2.2 方括号测试条件2.3 test 命令和测试条件可以判断的 3 类条件2.3.1 数值比较2.3.2 字符串比较 三、复合条件测试四、if-then 的高级特性五、case 命令 一、概述 上篇文章介绍了 if 语句相关知识。但 if 语句只能执行命令&#xff0c…...

基于单片机的语音识别智能垃圾桶垃圾分类的设计与实现

功能介绍 以51单片机作为主控系统&#xff1b;液晶显示当前信息和状态&#xff1b;通过语音识别模块对当前垃圾种类进行语音识别&#xff1b; 通过蜂鸣器进行声光报警提醒垃圾桶已满&#xff1b;采用舵机控制垃圾桶打开关闭&#xff1b;超声波检测当前垃圾桶满溢程度&#xff1…...

最新版本docker 设置国内镜像源 加速办法

解决问题:加速 docker 设置国内镜像源 目录: 国内加速地址 修改方法 国内加速地址 1.Docker中国区官方镜像 https://registry.docker-cn.com 2.网易 http://hub-mirror.c.163.com 3.ustc https://docker.mirrors.ustc.edu.cn 4.中国科技大学 https://docker.mirrors…...

深度学习——LSTM解决分类问题

RNN基本介绍 概述 循环神经网络&#xff08;Recurrent Neural Network&#xff0c;RNN&#xff09;是一种深度学习模型&#xff0c;主要用于处理序列数据&#xff0c;如文本、语音、时间序列等具有时序关系的数据。 核心思想 RNN的关键思想是引入了循环结构&#xff0c;允许…...

国防科技大学计算机基础课程笔记02信息编码

1.机内码和国标码 国标码就是我们非常熟悉的这个GB2312,但是因为都是16进制&#xff0c;因此这个了16进制的数据既可以翻译成为这个机器码&#xff0c;也可以翻译成为这个国标码&#xff0c;所以这个时候很容易会出现这个歧义的情况&#xff1b; 因此&#xff0c;我们的这个国…...

Spring Boot 实现流式响应(兼容 2.7.x)

在实际开发中&#xff0c;我们可能会遇到一些流式数据处理的场景&#xff0c;比如接收来自上游接口的 Server-Sent Events&#xff08;SSE&#xff09; 或 流式 JSON 内容&#xff0c;并将其原样中转给前端页面或客户端。这种情况下&#xff0c;传统的 RestTemplate 缓存机制会…...

在HarmonyOS ArkTS ArkUI-X 5.0及以上版本中,手势开发全攻略:

在 HarmonyOS 应用开发中&#xff0c;手势交互是连接用户与设备的核心纽带。ArkTS 框架提供了丰富的手势处理能力&#xff0c;既支持点击、长按、拖拽等基础单一手势的精细控制&#xff0c;也能通过多种绑定策略解决父子组件的手势竞争问题。本文将结合官方开发文档&#xff0c…...

关于nvm与node.js

1 安装nvm 安装过程中手动修改 nvm的安装路径&#xff0c; 以及修改 通过nvm安装node后正在使用的node的存放目录【这句话可能难以理解&#xff0c;但接着往下看你就了然了】 2 修改nvm中settings.txt文件配置 nvm安装成功后&#xff0c;通常在该文件中会出现以下配置&…...

将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?

Otsu 是一种自动阈值化方法&#xff0c;用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理&#xff0c;能够自动确定一个阈值&#xff0c;将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...

反射获取方法和属性

Java反射获取方法 在Java中&#xff0c;反射&#xff08;Reflection&#xff09;是一种强大的机制&#xff0c;允许程序在运行时访问和操作类的内部属性和方法。通过反射&#xff0c;可以动态地创建对象、调用方法、改变属性值&#xff0c;这在很多Java框架中如Spring和Hiberna…...

[Java恶补day16] 238.除自身以外数组的乘积

给你一个整数数组 nums&#xff0c;返回 数组 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法&#xff0c;且在 O(n) 时间复杂度…...

什么?连接服务器也能可视化显示界面?:基于X11 Forwarding + CentOS + MobaXterm实战指南

文章目录 什么是X11?环境准备实战步骤1️⃣ 服务器端配置(CentOS)2️⃣ 客户端配置(MobaXterm)3️⃣ 验证X11 Forwarding4️⃣ 运行自定义GUI程序(Python示例)5️⃣ 成功效果![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/55aefaea8a9f477e86d065227851fe3d.pn…...

dify打造数据可视化图表

一、概述 在日常工作和学习中&#xff0c;我们经常需要和数据打交道。无论是分析报告、项目展示&#xff0c;还是简单的数据洞察&#xff0c;一个清晰直观的图表&#xff0c;往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server&#xff0c;由蚂蚁集团 AntV 团队…...

深度学习习题2

1.如果增加神经网络的宽度&#xff0c;精确度会增加到一个特定阈值后&#xff0c;便开始降低。造成这一现象的可能原因是什么&#xff1f; A、即使增加卷积核的数量&#xff0c;只有少部分的核会被用作预测 B、当卷积核数量增加时&#xff0c;神经网络的预测能力会降低 C、当卷…...