问题描述

在做SpringSecurity 的用户权限功能时,登录用户实体类中需要获取权限信息。实体类继承UserDetails,通过方法 getAuthorities获取用户权限信息。

package org.javaboy.tienchin.common.core.domain.model;import java.util.ArrayList;
import java.util.Collection;
import java.util.Set;
import java.util.stream.Collectors;import org.javaboy.tienchin.common.core.domain.entity.SysUser;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import com.alibaba.fastjson2.annotation.JSONField;/*** 登录用户身份权限** @author tienchin*/
public class LoginUser implements UserDetails {private static final long serialVersionUID = 1L;/*** 用户ID*/private Long userId;/*** 部门ID*/private Long deptId;/*** 用户唯一标识*/private String token;/*** 登录时间*/private Long loginTime;/*** 过期时间*/private Long expireTime;/*** 登录IP地址*/private String ipaddr;/*** 登录地点*/private String loginLocation;/*** 浏览器类型*/private String browser;/*** 操作系统*/private String os;/*** 权限列表*/private Set<String> permissions;/*** 用户信息*/private SysUser user;public Long getUserId() {return userId;}public void setUserId(Long userId) {this.userId = userId;}public Long getDeptId() {return deptId;}public void setDeptId(Long deptId) {this.deptId = deptId;}public String getToken() {return token;}public void setToken(String token) {this.token = token;}public LoginUser() {}public LoginUser(SysUser user, Set<String> permissions) {this.user = user;this.permissions = permissions;}public LoginUser(Long userId, Long deptId, SysUser user, Set<String> permissions) {this.userId = userId;this.deptId = deptId;this.user = user;this.permissions = permissions;}@JSONField(serialize = false)@Overridepublic String getPassword() {return user.getPassword();}@Overridepublic String getUsername() {return user.getUserName();}/*** 账户是否未过期,过期无法验证*/@JSONField(serialize = false)@Overridepublic boolean isAccountNonExpired() {return true;}/*** 指定用户是否解锁,锁定的用户无法进行身份验证** @return*/@JSONField(serialize = false)@Overridepublic boolean isAccountNonLocked() {return true;}/*** 指示是否已过期的用户的凭据(密码),过期的凭据防止认证** @return*/@JSONField(serialize = false)@Overridepublic boolean isCredentialsNonExpired() {return true;}/*** 是否可用 ,禁用的用户不能身份验证** @return*/@JSONField(serialize = false)@Overridepublic boolean isEnabled() {return true;}public Long getLoginTime() {return loginTime;}public void setLoginTime(Long loginTime) {this.loginTime = loginTime;}public String getIpaddr() {return ipaddr;}public void setIpaddr(String ipaddr) {this.ipaddr = ipaddr;}public String getLoginLocation() {return loginLocation;}public void setLoginLocation(String loginLocation) {this.loginLocation = loginLocation;}public String getBrowser() {return browser;}public void setBrowser(String browser) {this.browser = browser;}public String getOs() {return os;}public void setOs(String os) {this.os = os;}public Long getExpireTime() {return expireTime;}public void setExpireTime(Long expireTime) {this.expireTime = expireTime;}public Set<String> getPermissions() {return permissions;}public void setPermissions(Set<String> permissions) {this.permissions = permissions;}public SysUser getUser() {return user;}public void setUser(SysUser user) {this.user = user;}@Overridepublic Collection<? extends GrantedAuthority> getAuthorities() {if (permissions != null && permissions.size() > 0) {return permissions.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList());}return new ArrayList<>();}
}

用户登录后,将该实体类存储在redis中,然后校验用户权限时,用携带的 token 再次从redis 中获取该用户信息。
代码片段:

    /*** 刷新令牌有效期** @param loginUser 登录信息*/public void refreshToken(LoginUser loginUser) {loginUser.setLoginTime(System.currentTimeMillis());loginUser.setExpireTime(loginUser.getLoginTime() + expireTime * MILLIS_MINUTE);// 根据uuid将loginUser缓存String userKey = getTokenKey(loginUser.getToken());redisCache.setCacheObject(userKey, loginUser, expireTime, TimeUnit.MINUTES);}/*** 获取用户身份信息** @return 用户信息*/public LoginUser getLoginUser(HttpServletRequest request) {// 获取请求携带的令牌String token = getToken(request);if (StringUtils.isNotEmpty(token)) {try {Claims claims = parseToken(token);// 解析对应的权限以及用户信息String uuid = (String) claims.get(Constants.LOGIN_USER_KEY);String userKey = getTokenKey(uuid);LoginUser user = redisCache.getCacheObject(userKey);return user;} catch (Exception e) {}}return null;}

在获取 LoginUser user = redisCache.getCacheObject(userKey);用户信息时,报错:fastjson2.JSONException: autoType is not support. org.springframework.security.core.authority.SimpleGrantedAuthority

原因分析:

通过报错信息容易知道是获取Redis 里的 LoginUser 信息,对LoginUser 信息进行反序列化时报错。
查看自己的Redis 序列化配置。

 @Bean@SuppressWarnings(value = {"unchecked", "rawtypes"})public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory) {RedisTemplate<Object, Object> template = new RedisTemplate<>();template.setConnectionFactory(connectionFactory);FastJson2JsonRedisSerializer serializer = new FastJson2JsonRedisSerializer(Object.class);ObjectMapper mapper = new ObjectMapper();mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);mapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);serializer.setObjectMapper(mapper);// 使用StringRedisSerializer来序列化和反序列化redis的key值template.setKeySerializer(new StringRedisSerializer());template.setValueSerializer(serializer);// Hash的key也采用StringRedisSerializer的序列化方式template.setHashKeySerializer(new StringRedisSerializer());template.setHashValueSerializer(serializer);template.afterPropertiesSet();return template;}

序列化配置:

package org.javaboy.tienchin.framework.config;import java.nio.charset.Charset;import com.alibaba.fastjson.parser.ParserConfig;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONReader;
import com.alibaba.fastjson2.JSONWriter;
import org.springframework.util.Assert;/*** Redis使用FastJson序列化** @author tienchin*/
public class FastJson2JsonRedisSerializer<T> implements RedisSerializer<T> {public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");@SuppressWarnings("unused")private ObjectMapper objectMapper = new ObjectMapper();private Class<T> clazz;public FastJson2JsonRedisSerializer(Class<T> clazz) {super();this.clazz = clazz;}static {ParserConfig.getGlobalInstance().setAutoTypeSupport(true);}@Overridepublic byte[] serialize(T t) throws SerializationException {if (t == null) {return new byte[0];}return JSON.toJSONString(t, JSONWriter.Feature.WriteClassName).getBytes(DEFAULT_CHARSET);}public void setObjectMapper(ObjectMapper objectMapper) {Assert.notNull(objectMapper, "'objectMapper' must not be null");this.objectMapper = objectMapper;}@Overridepublic T deserialize(byte[] bytes) throws SerializationException {if (bytes == null || bytes.length <= 0) {return null;}String str = new String(bytes, DEFAULT_CHARSET);return JSON.parseObject(str, clazz, JSONReader.Feature.SupportAutoType);}
}

解决方案:

通过网上查阅资料,实验过各种方法发现不能解决问题。但是发现,做序列化都是用的 fastjson,而我这里使用的是 fastjson2,将FastJson2JsonRedisSerializer 使用 fastjson 进行修改,并添加 ParserConfig.getGlobalInstance().setAutoTypeSupport(true),发现问题解决。

package org.javaboy.tienchin.framework.config;import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.TypeFactory;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
import com.alibaba.fastjson.parser.ParserConfig;
import org.springframework.util.Assert;import java.nio.charset.Charset;/*** Redis使用FastJson序列化** @author tienchin*/
public class FastJson2JsonRedisSerializer<T> implements RedisSerializer<T> {@SuppressWarnings("unused")private ObjectMapper objectMapper = new ObjectMapper();public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");private Class<T> clazz;static {ParserConfig.getGlobalInstance().setAutoTypeSupport(true);}public FastJson2JsonRedisSerializer(Class<T> clazz) {super();this.clazz = clazz;}@Overridepublic byte[] serialize(T t) throws SerializationException {if (t == null) {return new byte[0];}return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET);}@Overridepublic T deserialize(byte[] bytes) throws SerializationException {if (bytes == null || bytes.length <= 0) {return null;}String str = new String(bytes, DEFAULT_CHARSET);return JSON.parseObject(str, clazz);}public void setObjectMapper(ObjectMapper objectMapper) {Assert.notNull(objectMapper, "'objectMapper' must not be null");this.objectMapper = objectMapper;}protected JavaType getJavaType(Class<?> clazz) {return TypeFactory.defaultInstance().constructType(clazz);}
}

fastjson autoType is not support相关推荐

  1. java的autotype,关于 fastjson 异常 autoType is not support 问题分析解决

    数据仓库数据抽取服务在不久前增加了 OrientDB 的支持,当时使用了 Orient 官方提供的 JDBC 接口,后来发现 Orient JDBC 真是垃圾到无法言语了,不能满足我们自动化的 ETL ...

  2. 解决com.alibaba.fastjson.JSONException: autoType is not support

    转载自 https://blog.csdn.net/cdyjy_litao/article/details/72458538 最近发现进程运行日志中出现很多下面的日志: com.alibaba.fas ...

  3. fastjson报autotype is not support

    安全升级公告 最近发现fastjson在1.2.24以及之前版本存在远程代码执行高危安全漏洞,为了保证系统安全,请升级到1.2.28/1.2.29/1.2.30/1.2.31或者更新版本. 1.2.2 ...

  4. Fastjson AutoType

    Fastjson 1.2.24特性 Fastjson 1.2.24有两个特性: 默认开启AutoType选项 在处理以@type形式传入的类的时候,会默认调用该类的共有set\get\is函数 于是乎 ...

  5. 初探fastJson的AutoType

    文章目录 1. AutoType 何方神圣? 1.1 type字段 1.2 setAutoTypeSupport 2.反序列化攻击 3.AutoType 安全模式 4.参考 1. AutoType 何 ...

  6. fastjson到底做错了什么?为什么会被频繁爆出漏洞?

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 fastjson大家一定都不陌生,这是阿里巴巴的开源一个JSON解 ...

  7. Fastjson 1.2.68版本反序列化漏洞分析篇

    点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! 作者 | ale_wong@云影实验室 来源 | htt ...

  8. Fastjson 爆出远程代码执行高危漏洞,更新版本已修复

    漏洞介绍 fastjson在1.2.24以及之前版本近日曝出代码执行漏洞,当用户提交一个精心构造的恶意的序列化数据到服务器端时,fastjson在反序列化时存在漏洞,可导致远程任意代码执行漏洞. 风险 ...

  9. autotype安全 fastjson_Fastjson 安全更新,建议升级到 1.2.28 或更新版本

    安全升级公告 最近发现 fastjson 在 1.2.24 以及之前版本存在高危安全漏洞,为了保证系统安全,请升级到 1.2.28 或者更新版本. 更新方法 1. Maven 依赖配置更新 通过 ma ...

最新文章

  1. C中文件操作的文本模式和二进制模式,到底有啥区别?
  2. java单循环 比较得分_java – 为什么两个单独的循环比一个快?
  3. ubuntu16.04_install_saltstack_更新版本
  4. 如何得到别人的上网帐号和密码
  5. Linux下监控网卡流量的软件iftop
  6. 数据可视化组件Grafana详细解读--MacOSX上的安装
  7. ubuntu12的程序问题
  8. Linux 进程间通信 - 信号量
  9. 美国商务部发布软件物料清单 (SBOM) 的最小元素(中)
  10. 拓端tecdat|Matlab用深度学习长短期记忆(LSTM)神经网络对文本数据进行分类
  11. f2 柱状图滚动 钉钉小程序_钉钉小程序------子组件监测父组件的数据更新
  12. hdmi 屏幕旋转 树莓派_使用树莓派的轻量级远征工具套装
  13. windows加linux双系统安装方法
  14. Modbus 调试工具: Modbus poll与Modbus slave下载与使用(下)
  15. 《说服力》读后总结摘录
  16. 如何理解界面陷阱电荷呢(interface trapped charge)和费米钉扎效应?
  17. Element ui 组件中用键盘事件
  18. Android Studio混淆相关总结
  19. PCB设计软件-入门
  20. ES6、ES7、ES8、ES9、ES10新特性一览

热门文章

  1. 最小二乘法拟合圆公式推导及vc实现
  2. 百数在线表单如何实现表单套打?
  3. 看到“java单例模式”脑壳疼,学会这几招分分钟搞定
  4. 解决element Upload 上传 出现Access to XMLHttpRequest at
  5. Python发送微信消息(文字、图片、文件)给指定好友和微信群,零基础可看懂(附源码和教程)
  6. LightGBM是个什么东东?好像很耳熟啊,怎么玩啊?如何调参?一文搞定!
  7. 京东登月平台基础架构技术解析
  8. 用户界面设计10原则
  9. Qt实用技巧:实用掩码限制QLineEdit只能输入规定长度的数字、字母和字符
  10. 支付宝的架构到底有多牛逼?