org.springframework.data.redis.serializer.SerializationException: Could not read JSON: Unrecognized
最近写springSecurity redis遇到问题报错
org.springframework.data.redis.serializer.SerializationException: Could not read JSON: Unrecognized field "accountNonLocked" ]; line: 1, column: 18401] (through reference chain: JwtUser["accountNonLocked"])
在实现接口UserDetails过后报错,于是我查阅了大量的文章并且分析过源码,再加上一步一步的断点调试,总结出了以下结论
因为json反序列化原因UserDetails 这个里面对应getXXX(例如getPassword)的对象都要写对应的参数,否则json转义的时候会报错,如果用不到就增加注解@JsonIgnore。 |
对于权限Set集合因为json反序列化原因写入redis,再取出来会出现反序列化失败异常,所以此时我们应该写一个新的类来继承它让其序列化成功代码如下
package com.fan.security.authority;
/**
* @author およそ神
* @version JDK 1.8
*/
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.SpringSecurityCoreVersion;
import org.springframework.util.Assert;
public class MyGrantedAuthority implements GrantedAuthority {
private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;
private String authority;
public MyGrantedAuthority() {
super();
}
public MyGrantedAuthority(String authority) {
Assert.hasText(authority, "A granted authority textual representation is required");
this.authority = authority;
}
@Override
public String getAuthority() {
return authority;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof MyGrantedAuthority) {
return authority.equals(((MyGrantedAuthority) obj).authority);
}
return false;
}
@Override
public int hashCode() {
return this.authority.hashCode();
}
@Override
public String toString() {
return this.authority;
}
}
此时我们的UserDetailsService实现类如下
package com.fan.security;
import com.fan.security.authority.MyGrantedAuthority;
import com.fan.security.entity.SysPermission;
import com.fan.security.entity.SysUser;
import com.fan.security.service.SysPermissionService;
import com.fan.security.service.SysUserService;
import com.fan.security.vo.LoginUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* @author およそ神
* @version JDK 1.8
*/
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
private SysUserService sysUserService;
@Autowired
private SysPermissionService sysPermissionService;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//需要构造出 org.springframework.security.core.userdetails.User 对象并返回
if (username == null || "".equals(username)) {
throw new RuntimeException("用户不能为空");
}
//根据用户名查询用户
SysUser sysUser = sysUserService.selectByName(username);
if (sysUser == null) {
throw new RuntimeException("用户不存在");
}
Set<MyGrantedAuthority> grantedAuthorities = new HashSet<>();
if (sysUser != null) {
//获取该用户所拥有的权限
List<SysPermission> sysPermissions = sysPermissionService.selectListByUser(sysUser.getId());
// 声明用户授权
sysPermissions.forEach(sysPermission -> {
MyGrantedAuthority grantedAuthority = new MyGrantedAuthority(sysPermission.getPermissionCode());
grantedAuthorities.add(grantedAuthority);
});
}
sysUser.setGrantedAuthorities(grantedAuthorities);
return new LoginUser(sysUser);
}
}
这样一来我们用redis的set方法存进去的时候再取出来就不会报错了
@PostMapping(value = "/login")
public ResponseVO login(@RequestBody @Valid SysUserLoginDTO sysUserLoginDTO) {
//1、创建一个登录令牌类(Authentication的实现类) 名字密码身份验证
UsernamePasswordAuthenticationToken authenticationToken =
new UsernamePasswordAuthenticationToken
(sysUserLoginDTO.getAccount(), sysUserLoginDTO.getPassword());
//2、 用户验证 调用登录
Authentication authentication = null;
//它就会去 调用你写的com.hxzy.service.impl.UserDetailsServiceImpl类的方法
//传入需要验证的对象并调用验证方法赋值给authentication
authentication = this.authenticationManager.authenticate(authenticationToken);
if (authentication==null) throw new RuntimeException("登录失败,用户名或密码错误!");
//authentication.isAuthenticated()-->验证是否成功返回true or false
log.info("登录是否成功:{}", authentication.isAuthenticated());
//得到当前登录用户(本地线程池来做的,springsecurity框架做的)
// 与JwtAuthenticationTokenFilter 类 关联在一起的 principal
//获得被验证主题的身份强制转换成需要响应的tokenvo
LoginUser loginUser=(LoginUser) authentication.getPrincipal();
//生成把这个对象生成uuid,并且 把uuid变成jwt串
String userId = loginUser.getUser().getId().toString();
//创建新的令牌jwtStr
String jwtToken = JwtUtils.createJWTToken(userId);
SysUser user = loginUser.getUser();
boolean b = redisUtils.set("login" userId, user, 60L, TimeUnit.MINUTES);
System.out.println("redis设置是否成功:" b);
//返回一个带数据的响应VO
return ResponseVO.okHasData(jwtToken);
}
最后顺利完成jwt认证
package com.fan.security.config;
import com.alibaba.fastjson.JSONObject;
import com.fan.security.entity.SysUser;
import com.fan.security.vo.LoginUser;
import com.fan.utils.jwt.JwtUtils;
import com.fan.utils.redis.RedisUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Objects;
/**
* @author およそ神
* @version JDK 1.8
*/
@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
@Autowired
RedisUtils redisUtils;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String token = request.getHeader("token");
if (!StringUtils.hasText(token)) {
//放行
filterChain.doFilter(request, response);
return;
}
//解析token
String userId;
try {userId = JwtUtils.getIdByJWTToken(token);}
catch (Exception e) {throw new RuntimeException("token非法!");}
//从redis中获取信息
String redisKey = "login" userId;
SysUser loginUser = redisUtils.get(redisKey);
if (Objects.isNull(loginUser)) throw new RuntimeException("用户未登录!");
//重新登录一个springSecurity用户对象
UsernamePasswordAuthenticationToken authenticationToken=new UsernamePasswordAuthenticationToken(loginUser,null, loginUser.getGrantedAuthorities());//TODO 权限未完成
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
//放行,继续做下一步操作
filterChain.doFilter(request, response);
}
}
这篇好文章是转载于:学新通技术网
- 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
- 本站站名: 学新通技术网
- 本文地址: /boutique/detail/tanhfkgjaj
系列文章
更多
同类精品
更多
-
photoshop保存的图片太大微信发不了怎么办
PHP中文网 06-15 -
Android 11 保存文件到外部存储,并分享文件
Luke 10-12 -
word里面弄一个表格后上面的标题会跑到下面怎么办
PHP中文网 06-20 -
《学习通》视频自动暂停处理方法
HelloWorld317 07-05 -
photoshop扩展功能面板显示灰色怎么办
PHP中文网 06-14 -
微信公众号没有声音提示怎么办
PHP中文网 03-31 -
怎样阻止微信小程序自动打开
PHP中文网 06-13 -
excel下划线不显示怎么办
PHP中文网 06-23 -
excel打印预览压线压字怎么办
PHP中文网 06-22 -
photoshop蒙版画笔没反应怎么办
PHP中文网 06-24