一文上手SpringSecurity【九】

server/2024/12/22 2:09:59/

在校验token的过滤器当中, 由于需要根据用户名称, 去查询出要认证的对象,然后再去数据库当中查询出角色列表、权限列表.频繁的操作数据库,可能会带来性能瓶颈, 那么我们该如何解决呢?
我们可以引入Redis, 将认证的对象,存储到Redis当中,在校验token的过滤器当中,可以直接从Redis当中拿,这样就避免了频繁查询数据库的操作.

一、引入Redis

1.1 Redis配置

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

添加配置文件

spring:data:redis:host: ip地址port: 6379password: Rj1024client-type: lettucedatabase: 0

配置文件

java">@Configuration
public class RedisConfig {@Beanpublic RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();redisTemplate.setConnectionFactory(redisConnectionFactory);ObjectMapper objectMapper = new ObjectMapper();// 开启序列化LocalDate/LocalDateTime// jsr310里包括的.JavaTimeModule javaTimeModule = new JavaTimeModule();objectMapper.registerModule(javaTimeModule);objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(objectMapper, Object.class);// 设置key和value的序列化规则redisTemplate.setKeySerializer(new StringRedisSerializer());redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);// 设置hashKey和hashValue的序列化规则redisTemplate.setHashKeySerializer(new StringRedisSerializer());redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);// 设置支持事务redisTemplate.setEnableTransactionSupport(true);redisTemplate.afterPropertiesSet();return redisTemplate;}
}

二、修改业务逻辑

2.1 修改service层

在生成token的时候,我们直接返回给前端了,此处我们将token直接存储到Redis当中.
1
修改之后的代码如下所示:
2
修改校验token的过滤器,从Redis缓存中取数据
3
修改完代码如下所示
6

2.2 测试效果

启动服务器,请求,redis存储的数据如下所示
90
但是在校验token的过滤器当中, 从redis反序化出User对象的时候抛出了异常, 异常信息如下图所示
900
123
找到User源码, 查看一下, 发现User确实没有无参构造,造成反序列化错误
66
默认内置提供的User对象,不能满足我们的需求,此时我们只能自定义认证对象,自己去实现UserDetails接口了.

2.3 自定义认证对象

自定义一个类,实现UserDetails接口

java">JsonIncludeProperties({"tbSysUser", "authorityList"})
public class LoginUser implements UserDetails {private TbSysUser tbSysUser;// 用于接收权限列表, 通过此集合转换为Collection<? extends GrantedAuthority>类型的权限列表// 因为GrantedAuthority的实现类SimpleGrantedAuthority也没有无参构造,所以要避免序列化// SimpleGrantedAuthority对象,我们直接序列化List<String>// 在使用的时候,将List<String>转换为Collection<? extends GrantedAuthority>即可private List<String> authorityList;@JsonIgnore()private List<SimpleGrantedAuthority> simpleGrantedAuthorityList;public LoginUser() {}public LoginUser(TbSysUser tbSysUser, List<String> authorityList) {this.tbSysUser = tbSysUser;this.authorityList = authorityList;}@Overridepublic Collection<? extends GrantedAuthority> getAuthorities() {if(simpleGrantedAuthorityList != null){return simpleGrantedAuthorityList;}simpleGrantedAuthorityList = new ArrayList<SimpleGrantedAuthority>();for (String s : authorityList) {simpleGrantedAuthorityList.add(new SimpleGrantedAuthority(s));}return simpleGrantedAuthorityList;}@Overridepublic String getPassword() {return tbSysUser.getPassword();}@Overridepublic String getUsername() {return tbSysUser.getUsername();}@Overridepublic boolean isAccountNonExpired() {return true;}@Overridepublic boolean isAccountNonLocked() {return true;}@Overridepublic boolean isCredentialsNonExpired() {return true;}@Overridepublic boolean isEnabled() {return true;}
}

这里需要注意的是: GrantedAuthority的实现类SimpleGrantedAuthority也没有无参构造,所以要避免序列化.

修改UserDetailsService实现类
876
修改放入redis的对象
43
修改校验token的过滤器,从redis当中反序列化出LoginUser对象
89
redis当中保存的数据
123
测试一下效果
<a class=redis3" />
确实从缓存当中反序列化的数据,并没有去查询数据库.到此,替换完成.

三、总结

3.1 重点内容

  • 将认证对象放到缓存当中避免频繁的操作数据库
  • User对象、SimpleGrantedAuthority对象都没有无参构造, 导致jackson无法进行序列化,这里我们使用了自定义UserDetails对象的方式来解决
  • 注意jackson注解的使用

http://www.ppmy.cn/server/124989.html

相关文章

Spring Boot 整合MyBatis-Plus 实现多层次树结构的异步加载功能

文章目录 1&#xff0c;前言2&#xff0c;什么是多层次树结构&#xff1f;3&#xff0c;异步加载的意义4&#xff0c;技术选型与实现思路5&#xff0c;具体案例5.1&#xff0c;项目结构5.2&#xff0c;项目配置&#xff08;pom.xml&#xff09;5.3&#xff0c;配置文件&#xf…

uniapp js判断key是否在json中?

推荐学习文档 golang应用级os框架&#xff0c;欢迎stargolang应用级os框架使用案例&#xff0c;欢迎star案例&#xff1a;基于golang开发的一款超有个性的旅游计划app经历golang实战大纲golang优秀开发常用开源库汇总想学习更多golang知识&#xff0c;这里有免费的golang学习笔…

Spring Security中自定义cors配置

一、为什么要自定义cors配置 在使用Spring框架时&#xff0c;Spring Security组件提供了简便的cors配置方案&#xff0c;使程序开发者可以快速的实现“同源安全策略”。关于cors&#xff0c;可以参数之前的一篇文章--关于Spring Security的CORS_springsecurity cors-CSDN博客 由…

【Router】路由功能之端口转发(Port Forward)功能介绍及实现

端口转发(Port Forward) 端口转发是一种网络技术,它允许将传入到一个网络设备特定端口的网络流量转发到另一个设备的特定端口上,端口转发会创建一条通过路由器的路径,以便数据包可以到达网络内的设备。在路由器中创建端口转发可以打开对 Internet 上某些应用程序的访问。端…

动态规划算法专题(一):斐波那契数列模型

目录 1、动态规划简介 2、算法实战应用【leetcode】 2.1 题一&#xff1a;第N个泰波那契数 2.1.1 算法原理 2.1.2 算法代码 2.1.3 空间优化原理——滚动数组 2.1.4 算法代码——空间优化版本 2.2 题二&#xff1a;三步问题 2.2.1 算法原理 2.2.2 算法代码 2.3 题二&a…

unix中的vfork函数

一、前言 本文介绍unix中的vfork函数&#xff0c;vfork函数功能和fork函数类似&#xff0c;也是用于创建新的进程&#xff0c;只不过调用vfork函数创建的子进程将共享父进程的进程空间&#xff0c;且只有当子进程调用exec()或者exit()函数后&#xff0c;父进程才会继续运行。 …

vscode【实用插件】Notes 便捷做笔记

安装 在 vscode 插件市场的搜索 Notes点 安装 安装成功后&#xff0c;vscode 左侧栏会出现 使用 初次使用 需先选择一个本地目录 重启 vscode 后&#xff0c;得到 切换笔记目录 新建笔记 快捷键为 Alt N 默认会创建 .md 文件 配合插件 Markdown Preview Enhanced 预览 .md…

Spring Boot 学习之路 -- Service 层

前言 最近因为业务需要&#xff0c;被拉去研究后端的项目&#xff0c;代码框架基于 Spring Boot&#xff0c;对我来说完全小白&#xff0c;需要重新学习研究…出于个人习惯&#xff0c;会以 Blog 文章的方式做一些记录&#xff0c;文章内容基本来源于「 Spring Boot 从入门到精…