Spring Authorization Server优化篇:Redis值序列化器添加Jackson Mixin,解决Redis反序列化失败问题

前言

    在授权码模式的前后端分离的那篇文章中使用了Redis来保存用户的认证信息,在Redis的配置文件中配置的值序列化器是默认的Jdk序列化器,虽然这样也可以使用,但是在Redis客户端中查看时是乱码的(看起来是),如果切换为Jackson提供的值序列化器时又会在反序列化时失败,这样是不符合实际的,在项目框架搭建完毕或在已有项目中这些配置实际上应该都已经配置好了的,不能说为了这么一个功能去改原有配置,所以这里要跟大家说一声对不起,因为在下学艺不精而导致这么一个大缺陷一直留到了现在。😭

问题分析

    当时用到的地方就是在登录成功和初始化SecurityContextHolderFilter中初始化认证信息的地方存、取SecurityContext(认证信息),存的时候倒是没有问题,但是取的时候就会因为框架内的类不提供默认的构造器从而造成反序列化失败的问题,或者是类型转换异常

    Jackson 只能识别java基本类型,遇到复杂类型时,Jackson 就会先序列化成 LinkedHashMap,然后再尝试强转为所需类别,这样大部分情况下会强转失败,异常信息如下

java.lang.ClassCastException: class java.util.LinkedHashMap cannot be cast to class org.springframework.security.core.context.SecurityContext

这种情况需要添加一个配置,如下

objectMapper.activateDefaultTyping(  objectMapper.getPolymorphicTypeValidator(),  ObjectMapper.DefaultTyping.NON_FINAL,  JsonTypeInfo.As.PROPERTY);

但是当添加了这个配置后重启后再次尝试发现还是有异常,不过这时就是因为框架中的类没有提供默认构造器造成的,异常如下:

org.springframework.data.redis.serializer.SerializationException: Could not read JSON: Cannot construct instance of `org.springframework.security.authentication.UsernamePasswordAuthenticationToken` (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator)at [Source: (byte[])"{"@class":"org.springframework.security.core.context.SecurityContextImpl","authentication":{"@class":"org.springframework.security.authentication.UsernamePasswordAuthenticationToken","authorities":["java.util.Collections$UnmodifiableRandomAccessList",[{"@class":"com.example.model.security.CustomGrantedAuthority","authority":"system"},{"@class":"com.example.model.security.CustomGrantedAuthority","authority":"app"},{"@class":"com.example.model.security.CustomGrantedAuthority","authority":"web"}]],"[truncated 893 bytes]; line: 1, column: 184] (through reference chain: org.springframework.security.core.context.SecurityContextImpl["authentication"])

异常提示问题在SecurityContextImplauthentication属性上,因为该属性的实例是UsernamePasswordAuthenticationToken,这个类并没有一个默认的构造器,所以在反序列化时直接报错了,最开始时我的想法是写一个实现类,然后存取的时候用自定义的类中转一下,但是后来又发现了Json Mixin这个东西,发现这个玩意儿更方便,于是就实现了一下,写了一个UsernamePasswordAuthenticationMixin类来实现自定义反序列化逻辑,但是昨天突然发现这东西其实框架已经实现了😰就很尴尬,要将这些东西加进来添加一下框架提供的CoreJackson2Module就行,配置如下:

// 添加Security提供的Jackson Mixin  
objectMapper.registerModule(new CoreJackson2Module());

解决方案

Redis配置文件中配置的RedisTemplate添加值序列化器,值序列化器使用的ObjectMapper添加以上提到的那些配置,包括复杂类型映射、Security提供的Json Mixin,完整的Redis配置类如下

package com.example.config;import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.security.jackson2.CoreJackson2Module;/*** Redis的key序列化配置类** @author vains*/
@Configuration
@RequiredArgsConstructor
public class RedisConfig {private final Jackson2ObjectMapperBuilder builder;/*** 默认情况下使用** @param connectionFactory redis链接工厂* @return RedisTemplate*/@Beanpublic RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory) {// 字符串序列化器StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();// 创建ObjectMapper并添加默认配置ObjectMapper objectMapper = builder.createXmlMapper(false).build();// 序列化所有字段objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);// 此项必须配置,否则如果序列化的对象里边还有对象,会报如下错误://     java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to XXXobjectMapper.activateDefaultTyping(objectMapper.getPolymorphicTypeValidator(),ObjectMapper.DefaultTyping.NON_FINAL,JsonTypeInfo.As.PROPERTY);// 添加Security提供的Jackson MixinobjectMapper.registerModule(new CoreJackson2Module());// 存入redis时序列化值的序列化器Jackson2JsonRedisSerializer<Object> valueSerializer =new Jackson2JsonRedisSerializer<>(objectMapper, Object.class);RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();// 设置值序列化redisTemplate.setValueSerializer(valueSerializer);// 设置hash格式数据值的序列化器redisTemplate.setHashValueSerializer(valueSerializer);// 默认的Key序列化器为:JdkSerializationRedisSerializerredisTemplate.setKeySerializer(stringRedisSerializer);// 设置字符串序列化器redisTemplate.setStringSerializer(stringRedisSerializer);// 设置hash结构的key的序列化器redisTemplate.setHashKeySerializer(stringRedisSerializer);// 设置连接工厂redisTemplate.setConnectionFactory(connectionFactory);return redisTemplate;}/*** 操作hash的情况下使用** @param connectionFactory redis链接工厂* @return RedisTemplate*/@Beanpublic RedisTemplate<Object, Object> redisHashTemplate(RedisConnectionFactory connectionFactory) {return redisTemplate(connectionFactory);}}

扩展说明

从上边的配置可以看出Spring对于三方框架内部没有默认构造器的类的反序列化支持还是挺好的,如果集成其它框架时遇到这种情况时就可以仿照Security框架提供的Mixin类实现一个自己的Mixin类以支持反序列化,当然也可以找找在框架中是否有类似的Jackson2Module类;当自己封装一个starter时也可以提供Jackson2Module类来映射类,不过这个就按照个人的喜好来了,自己封装自由度很高的。

当然在使用Security时如果遇到其它反序列化失败的类,都可以在框架中找找有没有其它的Jackson2Module类,如果提供的有那就不用自己封装了,直接往ObjectMapper添加一个Module就行。

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

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

相关文章

leetcode刷题 二维数组 八方向

题目描述 输入&#xff1a;board [[0,1,0],[0,0,1],[1,1,1],[0,0,0]] 输出&#xff1a;[[0,0,0],[1,0,1],[0,1,1],[0,1,0]] 题目分析:就是以二维数组某个元素为中心&#xff0c;寻找周围八个方向的元素&#xff0c;按照题目要求修改二维数组元素返回&#xff1b; 拷贝一份二…

Git 代理(Proxy) 配置

某些情况下,我们需要通过代理才能访问特定网络环境下的git资源,git支持代理配置, 支持 http(s), SOCKS4/SOCKS5. HTTP(S) HTTP 代理配置格式如下: git config --global http.proxy http://[proxy]:[port]实际环境下, 其实我们大多数情况下,并不需要全部git资源都需要通过代理…

ElementUI实现登录注册+axios全局配置+CORS跨域

一、搭建项目 1.1 安装 Element-UI 先确保是否安装了vue-cli脚手架工具 !!! 安装vue脚手架可以看看我的上一篇博客 构建好项目后通过npm安装element-ui cd 项目根路径 #进入新建项目的根目录 npm install element-ui -S #安装…

AUTOSAR 面试知识回顾

如果答不上来&#xff0c;就讲当时做了什么 1. Ethernet基础: 硬件接口&#xff1a; ECU到PHY&#xff1a; data 是MII总线&#xff0c; 寄存器控制是SMI总线【MDCMDIO两根线, half duplex】PHY输出(100BASE-T1)&#xff1a; MDI总线&#xff0c;2 wire 【T1: twisted 1 pair …

C#__简单使用TCP/UDP发送消息

Socket(套接字、插口) TCP和UCP的区别&#xff1a; 1、基于连接和无连接 2、对系统资源的要求&#xff08;TCP较多&#xff0c;UCP少&#xff09; 3、UDP程序结构简单 4、流模式和数据报模式 5、TCP保证数据正确性和数据先后顺…

Java21虚拟线程实践

文章目录 虚拟线程的使用什么是虚拟线程虚拟线程和协程相同之处&#xff1a;不同之处&#xff1a; 总结 就在前几天&#xff0c;java21正式版发布了&#xff0c;作为继java17之后的又一个长期支持版本 (LTS)&#xff0c;为我们带来了很多新的特性&#xff0c;其中我最感兴趣的就…

【线性代数】

0、线性代数的本质往往被淹没在计算的海洋中&#xff0c;无人问津&#xff01; 1、什么是向量&#xff1f; 向量是带方向的箭头&#xff0c;向量是坐标。 2、向量的线性组合 两个向量不共线&#xff0c;即线性无关&#xff1b;两个向量共线&#xff0c;即线性相关。 两个不…

关于地址存放的例题

unsigned int a 0x1234; unsigned char b *(unsigned char*)&a; 上面代码大端存储和小端存储的值分别是多少&#xff1f; 大端存储的是把高位地址存放在低位地址处&#xff0c;低位存放到高位。小端是高位存放在高位&#xff0c;低位在低位。因为a是整型&#xff0c;所…

GraphQL基础知识与Spring for GraphQL使用教程

文章目录 1、数据类型1.1、标量类型1.2. 高级数据类型 基本操作2、Spring for GraphQL实例2.1、项目目录2.2、数据库表2.3、GraphQL的schema.graphql2.4、Java代码 3、运行效果3.1、添加用户3.2、添加日志3.3、查询所有日志3.4、查询指定用户日志3.5、数据订阅 4、总结 GraphQL…

C 语言简单入门

C 语言发展历史|标准 1972年&#xff0c;丹尼斯里奇&#xff08;Dennis Ritch&#xff09;和肯汤普逊&#xff08;Ken Tompson&#xff09;在贝尔实验室开发 UNIX 操作系统时基于 B 语言设计出 C 语言。 1987年&#xff0c;布莱恩柯林汉&#xff08;Brian Kernighan&#xff…

数据库基础理论

什么是数据库&#xff1f; 数据&#xff1a;描述事物的符号记录&#xff0c;可以是数字、文字、图形、图像、声音、语言等&#xff0c;数据有多种形式&#xff0c;他们都是可以经过数字化后存入计算机。 数据库&#xff1a;存储数据的仓库&#xff0c;是长期存放在计算机内、…

世界前沿技术发展报告2023《世界信息技术发展报告》(三)量子信息技术

&#xff08;三&#xff09;量子信息技术 1. 概述2. 量子计算2.1 阿里巴巴达摩院成功研制两比特量子芯片&#xff0c;单比特操控精度超99.97%2.2 加拿大Xanadu公司开发出可编程光量子计算机2.3 美国英伟达公司为经典-量子混合计算推出开发架构2.4 日本国家自然科学研究所开发出…

SpringBoot实战

ISBN: 978-7-115-43314-5 作者&#xff1a;【美】Craig Walls 译者&#xff1a;丁雪丰 页数&#xff1a;209页 阅读时间&#xff1a;2022-12-27 推荐指数&#xff1a;★★★☆☆ 阅读本书还是要有一定的基础的&#xff0c;如果想要入门级还是不行&#xff0c; 建议入门级可以看…

python+nodejs+php+springboot+vue 法律知识分享科普系统平台

在设计过程中&#xff0c;充分保证了系统代码的良好可读性、实用性、易扩展性、通用性、便于后期维护、操作方便以及页面简洁等特点。 随着社会的发展&#xff0c;社会的各行各业都在利用信息化时代的优势。计算机的优势和普及使得各种信息系统的开发成为必需。 要想实现法律知…

数字图像基础,数字图像处理中的基础内容(数字图像处理概念 P2)

文章目录 人类视觉系统构造数字图像生成采样和量化像素之间的基本关系 人类视觉系统构造 锥状体&#xff1a;明亮的视野杆状体&#xff1a;微光或暗视野图像成像原理&#xff1a;类似照相机亮度适应现象&#xff1a;人的视觉不能同时在一个范围内工作同时对比现象&#xff1a;…

el-select的某一项选中后显示id

环境: vue3element-plus 今天在使用elementui的下拉组件的时候发现有一个选项在选中后显示的是id.找了会没看到问题,后来想到会不会是没有设置key的原因(之前看到说vue3可以不用设置key),果然加上key就可以了

README

title: “README” createTime: 2022-01-04T20:48:4008:00 updateTime: 2022-01-04T20:48:4008:00 draft: false author: “name” tags: [“shell”] categories: [“hadoop”] description: “测试的” hadoop 相关技术 获取某个application的 日志 yarn logs -application…

变量、因子、缺失值、类型转换、剔除多余变量、随机抽样、用R使用SQL、trim、na.rm=TRUE、数据标准化应用

变量&#xff1a;名义型、有序型、连续型变量 名义型&#xff1a;普通事件类型&#xff0c;如糖尿病I型和糖尿病II型。 有序型&#xff1a;有顺序的事件类型&#xff0c;如一年级、二年级和三年级。 连续型&#xff1a;表示有顺序的数量&#xff0c;如年龄。 因子&#xff1a;…

基于Python+Django的热门旅游景点数据分析系统的设计与实现(源码+lw+部署文档+讲解等)

前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战✌&#x1f497; &#x1f447;&#x1f3fb;…

C++项目:仿muduo库实现高性能高并发服务器

文章目录 一、实现目标二、前置知识&#xff08;一&#xff09;HTTP服务器1.概念 &#xff08;二&#xff09;Reactor模型&#xff1a;1.概念2.分类&#xff08;1&#xff09;单Reactor单线程&#xff1a;单I/O多路复用业务处理。&#xff08;2&#xff09;单Reactor多线程&…