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实现用户认证-阿里云开发者社区 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HideSeeker论文阅读

文章目录 3.1 Overview of Our System HideSeeker3.2 Visual Information Extraction3.3 Relation Graph Learning3.4 Hidden Object Inference 4 EVALUATIONS4.7 Summary 6 DISCUSSIONS AND CONCLUSION 3.1 Overview of Our System HideSeeker 我们设计了一种名为“HideSeeke…

个人博客系统(SSM版 前端+后端)

前言 在学习Servlet的时候,也写了一个博客系统,主要的就是使用servelet加Tomcat进行实现的,而这个项目 仅仅适合去学习Web项目开发的思想,并不满足当下企业使用框架的思想,进行学习过Spring,Spring Boot,Spring MVC以及MyBatis之后,我们就可以对之前的项目使用SSM框架的形式进行…

95、Kafka是pull?push?优劣势分析

Kafka是pull&#xff1f;push&#xff1f;优劣势分析 一、pull模式二、push模式三、额外补充 一、pull模式 根据consumer的消费能力进行数据拉取&#xff0c;可以控制速率可以批量拉取、也可以单条拉取可以设置不同的提交方式&#xff0c;实现不同的传输语义 缺点: 如果kafka…

webpack环境配置的问题

1.如何区分不同的配置 // vue.config.js 中定义不同配置项 module.exports {// 默认配置// ...// 开发环境配置dev: {// ...},// 生产环境配置prod: {// ...} };// 在运行 vue-cli-service 命令时&#xff0c;在package.json中设置不同配置 {"scripts": {"ser…

react+redux异步操作数据

reactredux异步操作数据 redux中操作异步方法&#xff0c;主要是&#xff1a; 1、借助createAsyncThunk()封装异步方法&#xff1b;2、通过extraReducers处理异步方法触发后的具体逻辑&#xff0c;操作派生的state 1、异步操作的slice import { createSlice, createAsyncThunk…

uniapp 之 微信小程序、支付宝小程序 对于自定义导航栏的不同

目录 前言 微信小程序 代码 支付宝小程序 首页配置文件 二级菜单页面 配置 总结 不同 相同 前言 小程序都是 uni-app 写的 不是原生 微信小程序 代码 pages.json文件中配置 重点&#xff1a; "navigationStyle": "custom", // 导航栏样式…

【N32L40X】学习笔记05-串口库(空闲中断+接收非空中断)

串口 该函数库的目的就是在统一的地方配置&#xff0c;将配置的不同项放置在一个结构体内部使用一个枚举来定义一个的别名 bsp_uart.h #ifndef _BSP_UART_H_ #define _BSP_UART_H_ #include<stdio.h> #include<stdint.h> #include "n32l40x.h"#define…

ChatGPT开放自定义系统级别的指令,可设置偏好变成专属助理

OpenAI官方消息https://openai.com/blog/custom-instructions-for-chatgpt OpenAI为其大型语言模型接口ChatGPT引入了自定义指令&#xff0c;旨在为用户提供更加量身定制和个性化的体验&#xff0c;可以设置您的偏好&#xff0c;ChatGPT将在未来的所有对话中记住它们。 该功…

Redis高可用部署架构

目录 1. 主从复制与哨兵架构&#xff1a;2. Redis集群架构&#xff1a; Redis高可用部署可以采用主从复制与哨兵架构或Redis集群架构。下面将分别介绍这两种架构的架构图、优缺点和具体应用场景。 1. 主从复制与哨兵架构&#xff1a; 架构图&#xff1a; ----------| Client…

Python—数据结构(一)

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

Go语言通过反射获取各种类型变量的值

Go语言通过反射获取各种类型变量的值 反射是程序在运行期间获取变量的类型和值、或者执行变量的方法的能力。 1、什么是反射 反射是程序在运行期间获取变量的类型和值、或者执行变量的方法的能力。 Golang 反射包中有两对非常重要的函数和类型&#xff0c;两个函数分别是&a…

音视频开发-ffmpeg介绍-系列二

目录 一、FFmpeg核心结构体 二、解码流程 三、FFmpeg解码实现 四、FFmpeg编码实现 五、FFmpeg转码实现 一、FFmpeg核心结构体 AVFormatContext&#xff1a;解封装功能的结构体&#xff0c;包含文件名、音视频流、时长、比特率等信息&#xff1b; AVCodecContext&#xf…

【算法基础:数学知识】4.3 欧拉函数

文章目录 欧拉函数定义性质 例题列表873. 欧拉函数&#xff08;使用质因数分解求一个数的欧拉函数&#xff09;原理讲解&#xff08;公式推导&#xff09;⭐解法代码 874. 筛法求欧拉函数&#xff08;求 1 ~ n 中所有数字的欧拉函数&#xff09;⭐ 欧拉函数 https://oi-wiki.o…

[数据结构 -- 手撕排序算法第六篇] 递归实现快速排序(集霍尔版本,挖坑法,前后指针法为一篇的实现方法,很能打)

目录 1、常见的排序算法 1.1 交换排序基本思想 2、快速排序的实现方法 2.1 基本思想 3 hoare&#xff08;霍尔&#xff09;版本 3.1 实现思路 3.2 思路图解 3.3 为什么实现思路的步骤2、3不能交换 3.4 hoare版本代码实现 3.5 hoare版本代码测试 4、挖坑法 4.1 实现…

Java设计模式解析:迭代器模式的实现与应用

迭代器模式是一种行为型设计模式&#xff0c;它提供了一种统一的方式来遍历集合中的元素&#xff0c;而无需暴露集合的内部结构。在本文中&#xff0c;我们将深入探讨迭代器模式的实现和应用。 在软件开发中&#xff0c;集合是一种常见的数据结构&#xff0c;用于存储和管理一…

【手撕排序算法】---基数排序

个人主页&#xff1a;平行线也会相交 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 平行线也会相交 原创 收录于专栏【数据结构初阶&#xff08;C实现&#xff09;】 我们直到一般的排序都是通过关键字的比较和移动这两种操作来进行排序的。 而今天介绍的…

​MySQL高阶语句(三)

目录 1、内连接 2、左连接 3、右连接&#xff1a; 二、存储过程⭐⭐⭐ 4. 调用存储过程 5.查看存储过程 5.1 查看存储过程 5.2查看指定存储过程信息 三. 存储过程的参数 3.1存储过程的参数 3.2修改存储过程 四.删除存储过程 MySQL 的连接查询&#xff0c;通常都是将来…

微服务一 实用篇 - 5.分布式搜索引擎(ElasticSearch基础)

《微服务一 实用篇 - 5.分布式搜索引擎&#xff08;ElasticSearch基础&#xff09;》 提示: 本材料只做个人学习参考,不作为系统的学习流程,请注意识别!!! 《微服务一 实用篇 - 5.分布式搜索引擎&#xff08;ElasticSearch基础&#xff09;》 《微服务一 实用篇 - 5.分布式搜索…

【广州华锐互动】列车人员疏散VR虚拟演练系统

随着科技的不断发展&#xff0c;虚拟现实(VR)技术已经逐渐应用于各个领域。在火车站安全方面&#xff0c;为了提高旅客的安全意识和应对突发事件的能力&#xff0c;列车人员疏散VR虚拟演练系统应运而生。 列车人员疏散VR虚拟演练系统是一种基于虚拟现实技术的教育培训系统&…

数据结构问答7

1. 图的定义和相关术语 答: 定义:图是由顶点集V和边集E组成,其中V为有限非空集。 相关术语:n个顶点,e条边,G=(V,E) ① 邻接点和端点:无向图中,若存在一条边(i, j),则称i,j为该边的端点,且它们互为邻接点;在有向图中,若存在一条边<i, j>,则称i,j分别为…