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

news/2024/5/17 16:26:38

一言以蔽之,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实现用户认证-阿里云开发者社区 


http://www.mrgr.cn/p/55443136

相关文章

HTTP、HTTPS协议详解

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

2023 蓝桥杯真题B组 C/C++

https://www.dotcpp.com/oj/train/1089/ 题目 3150: 蓝桥杯2023年第十四届省赛真题-冶炼金属 题目描述 小蓝有一个神奇的炉子用于将普通金属 O 冶炼成为一种特殊金属 X。这个炉子有一个称作转换率的属性 V&#xff0c;V 是一个正整数&#xff0c;这意味着消耗 V 个普通金 属 O…

react-native 输入框 被软键盘遮挡 (KeyboardAvoidingView)

本组件用于解决一个常见的尴尬问题&#xff1a;手机上弹出的键盘常常会挡住当前的视图。本组件可以自动根据键盘的高度&#xff0c;调整自身的 height 或底部的 padding&#xff0c;以避免被遮挡。 <KeyboardAvoidingViewbehavior{Platform.OS ios ? padding : height}key…

【点云处理教程】02从 Python 中的深度图像估计点云

一、说明 这是“点云处理”教程的第二篇文章。“点云处理”教程对初学者友好&#xff0c;我们将在其中简单地介绍从数据准备到数据分割和分类的点云处理管道。在本教程中&#xff0c;我们将学习如何在不使用 Open3D 库的情况下从深度图像计算点云。我们还将展示如何优化代码以获…

【VUE】解决图片视频加载缓慢/首屏加载白屏的问题

1 问题描述 在 Vue3 项目中&#xff0c;有时候会出现图片视频加载缓慢、首屏加载白屏的问题 2 原因分析 通常是由以下原因导致的&#xff1a; 图片或视频格式不当&#xff1a;如果图片或视频格式选择不当&#xff0c;比如选择了无损压缩格式&#xff0c;可能会导致文件大小过大…

微信小程序交易体验分常见问题指引

小程序交易体验分是为保障小程序用户的交易体验&#xff0c;促进开发者向用户提供更好的服务&#xff0c;帮助开发者更好的评估自身服务水平的机制。平台将对开发者在其小程序的违规行为进行判定&#xff0c;根据违规行为的严重程度对该小程序扣减不同分值的交易体验分&#xf…

风靡朋友圈的妙鸭相机,到底用了哪些底层技术?

不知道大家近期的朋友圈有没有被和海马体、天真蓝如出一辙的AI写真刷屏&#xff01; 这些面若桃花、精致到头发丝、光影充满氛围感的写真都是一款叫“妙鸭相机”的小程序生成的&#xff01;只要9.9&#xff0c;就能体验999写真&#xff01; 虽然只要9.9&#xff0c;但生成的照片…

opencv-24 图像几何变换03-仿射-cv2.warpAffine()

什么是仿射&#xff1f; 仿射变换是指图像可以通过一系列的几何变换来实现平移、旋转等多种操作。该变换能够 保持图像的平直性和平行性。平直性是指图像经过仿射变换后&#xff0c;直线仍然是直线&#xff1b;平行性是指 图像在完成仿射变换后&#xff0c;平行线仍然是平行线。…

海康摄像头开发笔记(一):连接防爆摄像头、配置摄像头网段、设置rtsp码流、播放rtsp流、获取rtsp流、调优rtsp流播放延迟以及录像存储

文为原创文章&#xff0c;转载请注明原文出处 本文章博客地址&#xff1a;https://hpzwl.blog.csdn.net/article/details/131679108 红胖子(红模仿)的博文大全&#xff1a;开发技术集合&#xff08;包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结…

服务器 Docker Alist挂载到本地磁盘(Mac版)夸克网盘

1.服务器下载alist 默认有docker环境 docker pull xhofe/alist2.生成容器 -v /home/alist:/opt/alist/data 这段意思是alist中的数据映射到docker 主机的文件夹&#xff0c;/home/alist就是我主机的文件夹&#xff0c;这个文件夹必须先创建 docker run -d --restartalways…

【Python】数据分析+数据挖掘——探索Pandas中的数据筛选

1. 前言 当涉及数据处理和分析时&#xff0c;Pandas是Python编程语言中最强大、灵活且广泛使用的工具之一。Pandas提供了丰富的功能和方法&#xff0c;使得数据的选择、筛选和处理变得简单而高效。在本博客中&#xff0c;我们将重点介绍Pandas中数据筛选的关键知识点&#xff…

ChatGPT结合知识图谱构建医疗问答应用 (一) - 构建知识图谱

一、ChatGPT结合知识图谱 在本专栏的前面文章中构建 ChatGPT 本地知识库问答应用&#xff0c;都是基于词向量检索 Embedding 嵌入的方式实现的&#xff0c;在传统的问答领域中&#xff0c;一般知识源采用知识图谱来进行构建&#xff0c;但基于知识图谱的问答对于自然语言的处理…

Nginx配置WebSocket反向代理

1、WebSocket协议 ​ WebSocket协议相比较于HTTP协议成功握手后可以多次进行通讯&#xff0c;直到连接被关闭。但是WebSocket中的握手和HTTP中的握手兼容&#xff0c;它使用HTTP中的Upgrade协议头将连接从HTTP升级到WebSocket。这使得WebSocket程序可以更容易的使用现已存在的…

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

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

记一次安装nvm切换node.js版本实例详解

最后效果如下&#xff1a; 背景&#xff1a;由于我以前安装过node.js&#xff0c;后续想安装nvm将node.js管理起来。 问题&#xff1a;nvm-use命令行运行成功&#xff0c;但是nvm-list显示并没有成功。 原因&#xff1a;因为安装过node.js&#xff0c;所以原先的node.js不收n…

CloudStudio搭建Next框架博客_抛开电脑性能在云端编程(沉浸式体验)

文章目录 ⭐前言⭐进入cloud studio工作区指引&#x1f496; 注册coding账号&#x1f496; 选择cloud studio&#x1f496; cloud studio选择next.js&#x1f496; 安装react的ui框架&#xff08;tDesign&#xff09;&#x1f496; 安装axios&#x1f496; 代理请求跨域&#x…

2.获取DOM元素

获取DOM元素就是利用JS选择页面中的标签元素 2.1 根据CSS选择器来获取DOM元素(重点) 2.1.1选择匹配的第一个元素 语法: document.querySelector( css选择器 )参数: 包含一个或多个有效的CSS选择器 字符串 返回值: CSS选择器匹配的第一个元素&#xff0c;一个HTMLElement对象…

Data Structure, Algorithm,and Applications in C++

在学习这本书进阶内容之前&#xff0c;我们可以跟着它的第一章部分再巩固和复习。本书由Sartaj Sahni撰写&#xff0c;由王立柱和刘志红翻译。全书通俗易懂&#xff0c;内容丰富&#xff0c;是巩固C内容的不二选择。希望本文对各位有所帮助。 目录 1.函数与参数 1.1.传值参数…

【Linux】用户相关内容

如果命令ll 出现以上信息&#xff0c;UID为具体的数字&#xff0c;代表之前UID为502的用户被删除了。 更改目录或文件所属用户和所属组 在Linux中&#xff0c;创建一个文件时&#xff0c;该文件的拥有者都是创建该文件的用户。 更改所属用户 chown 用户名 文件名/目录名 更…

:is()、:where() 和 :has() 伪元素

:is()、:where() 和 :has() 伪元素是 CSS 中用于样式化元素的非常强大的工具。它们是在 CSS 选择器 Level 4 规范中引入的。它们允许我们将样式应用于符合特定条件的任何元素&#xff0c;例如元素的类型、元素的位置和元素的后代。 :is() :is() - CSS&#xff1a;层叠样式表 …