网站建设相对路径电话网站域名到期
news/
2025/10/2 14:36:56/
文章来源:
网站建设相对路径,电话网站域名到期,网站维护是不是很难做,注册企业的步骤前言 在授权码模式的前后端分离的那篇文章中使用了Redis来保存用户的认证信息#xff0c;在Redis的配置文件中配置的值序列化器是默认的Jdk序列化器#xff0c;虽然这样也可以使用#xff0c;但是在Redis客户端中查看时是乱码的(看起来是)#xff0c;如果切换为Jackson提供…前言 在授权码模式的前后端分离的那篇文章中使用了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])异常提示问题在SecurityContextImpl的authentication属性上因为该属性的实例是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 RedisTemplateObject, 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时序列化值的序列化器Jackson2JsonRedisSerializerObject valueSerializer new Jackson2JsonRedisSerializer(objectMapper, Object.class);RedisTemplateObject, 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 RedisTemplateObject, Object redisHashTemplate(RedisConnectionFactory connectionFactory) {return redisTemplate(connectionFactory);}}扩展说明
从上边的配置可以看出Spring对于三方框架内部没有默认构造器的类的反序列化支持还是挺好的如果集成其它框架时遇到这种情况时就可以仿照Security框架提供的Mixin类实现一个自己的Mixin类以支持反序列化当然也可以找找在框架中是否有类似的Jackson2Module类当自己封装一个starter时也可以提供Jackson2Module类来映射类不过这个就按照个人的喜好来了自己封装自由度很高的。
当然在使用Security时如果遇到其它反序列化失败的类都可以在框架中找找有没有其它的Jackson2Module类如果提供的有那就不用自己封装了直接往ObjectMapper添加一个Module就行。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/924996.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!