当前位置: 首页 > news >正文

如何免费做网站推广的推广软件平台

如何免费做网站推广的,推广软件平台,网站开发案例详解 源代码,中小企业上市公司名单最近在使用SpringSecurityJWT实现认证授权的时候#xff0c;出现Redis在反序列化userDetails的异常。通过实践发现#xff0c;使用不同的序列化方法和不同的fastJson版本#xff0c;异常信息各不相同。所以特地记录了下来。 一、项目代码 先来看看我项目中redis相关配置信息…        最近在使用SpringSecurityJWT实现认证授权的时候出现Redis在反序列化userDetails的异常。通过实践发现使用不同的序列化方法和不同的fastJson版本异常信息各不相同。所以特地记录了下来。 一、项目代码 先来看看我项目中redis相关配置信息。 1.自定义的redis序列化器 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 mosul*/ public class FastJsonRedisSerializerT implements RedisSerializerT {public static final Charset DEFAULT_CHARSET Charset.forName(UTF-8);private ClassT clazz;static{ParserConfig.getGlobalInstance().setAutoTypeSupport(true);}public FastJsonRedisSerializer(ClassT 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);}protected JavaType getJavaType(Class? clazz){return TypeFactory.defaultInstance().constructType(clazz);} } 2.redis配置类 import com.alibaba.fastjson.support.spring.GenericFastJsonRedisSerializer; 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.StringRedisSerializer;Configuration public class RedisConfig {/*** 指定特定的连接工厂* return*//*Beanpublic RedisConnectionFactory redisConnectionFactory() {return new LettuceConnectionFactory();}*/BeanSuppressWarnings(value { unchecked, rawtypes })public RedisTemplateObject, Object redisTemplate(RedisConnectionFactory connectionFactory){RedisTemplateObject, Object template new RedisTemplate();template.setConnectionFactory(connectionFactory);FastJsonRedisSerializer serializer new FastJsonRedisSerializer(Object.class);// 使用StringRedisSerializer来序列化和反序列化redis的key值template.setKeySerializer(new StringRedisSerializer());template.setValueSerializer(serializer);// Hash的key也采用StringRedisSerializer的序列化方式template.setHashKeySerializer(new StringRedisSerializer());template.setHashValueSerializer(serializer);template.afterPropertiesSet();return template;} } 3.redis工具类 import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.BoundSetOperations; import org.springframework.data.redis.core.HashOperations; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.ValueOperations; import org.springframework.stereotype.Component;import java.util.*; import java.util.concurrent.TimeUnit;/*** Redis帮助类** author mosul*/ SuppressWarnings(value { unchecked, rawtypes }) Component public class RedisHelper {Autowiredpublic RedisTemplate redisTemplate;/*** 缓存基本的对象Integer、String、实体类等** param key 缓存的键值* param value 缓存的值*/public T void setCacheObject(final String key, final T value){redisTemplate.opsForValue().set(key, value);}/*** 缓存基本的对象Integer、String、实体类等** param key 缓存的键值* param value 缓存的值* param timeout 时间* param timeUnit 时间颗粒度*/public T void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit){redisTemplate.opsForValue().set(key, value, timeout, timeUnit);}/*** 设置有效时间** param key Redis键* param timeout 超时时间* return true设置成功false设置失败*/public boolean expire(final String key, final long timeout){return expire(key, timeout, TimeUnit.SECONDS);}/*** 设置有效时间** param key Redis键* param timeout 超时时间* param unit 时间单位* return true设置成功false设置失败*/public boolean expire(final String key, final long timeout, final TimeUnit unit){return redisTemplate.expire(key, timeout, unit);}/*** 获得缓存的基本对象。** param key 缓存键值* return 缓存键值对应的数据*/public T T getCacheObject(final String key){ValueOperationsString, T operation redisTemplate.opsForValue();return operation.get(key);}/*** 删除单个对象** param key*/public boolean deleteObject(final String key){return redisTemplate.delete(key);}/*** 删除集合对象** param collection 多个对象* return*/public long deleteObject(final Collection collection){return redisTemplate.delete(collection);}/*** 缓存List数据** param key 缓存的键值* param dataList 待缓存的List数据* return 缓存的对象*/public T long setCacheList(final String key, final ListT dataList){Long count redisTemplate.opsForList().rightPushAll(key, dataList);return count null ? 0 : count;}/*** 获得缓存的list对象** param key 缓存的键值* return 缓存键值对应的数据*/public T ListT getCacheList(final String key){return redisTemplate.opsForList().range(key, 0, -1);}/*** 缓存Set** param key 缓存键值* param dataSet 缓存的数据* return 缓存数据的对象*/public T BoundSetOperationsString, T setCacheSet(final String key, final SetT dataSet){BoundSetOperationsString, T setOperation redisTemplate.boundSetOps(key);IteratorT it dataSet.iterator();while (it.hasNext()){setOperation.add(it.next());}return setOperation;}/*** 获得缓存的set** param key* return*/public T SetT getCacheSet(final String key){return redisTemplate.opsForSet().members(key);}/*** 缓存Map** param key* param dataMap*/public T void setCacheMap(final String key, final MapString, T dataMap){if (dataMap ! null) {redisTemplate.opsForHash().putAll(key, dataMap);}}/*** 获得缓存的Map** param key* return*/public T MapString, T getCacheMap(final String key){return redisTemplate.opsForHash().entries(key);}/*** 往Hash中存入数据** param key Redis键* param hKey Hash键* param value 值*/public T void setCacheMapValue(final String key, final String hKey, final T value){redisTemplate.opsForHash().put(key, hKey, value);}/*** 获取Hash中的数据** param key Redis键* param hKey Hash键* return Hash中的对象*/public T T getCacheMapValue(final String key, final String hKey){HashOperationsString, String, T opsForHash redisTemplate.opsForHash();return opsForHash.get(key, hKey);}/*** 删除Hash中的数据** param key* param hkey*/public void delCacheMapValue(final String key, final String hkey){HashOperations hashOperations redisTemplate.opsForHash();hashOperations.delete(key, hkey);}/*** 获取多个Hash中的数据** param key Redis键* param hKeys Hash键集合* return Hash对象集合*/public T ListT getMultiCacheMapValue(final String key, final CollectionObject hKeys){return redisTemplate.opsForHash().multiGet(key, hKeys);}/*** 获得缓存的基本对象列表** param pattern 字符串前缀* return 对象列表*/public CollectionString keys(final String pattern){return redisTemplate.keys(pattern);} } 4.自己系统中的UserDetails Data NoArgsConstructor AllArgsConstructor public class LoginUser implements UserDetails {private static final long serialVersionUID 1L;// 系统用户private SysUser user;// 用户权限列表private ListSysPermission permissionList;Overridepublic Collection? extends GrantedAuthority getAuthorities() {return permissionList.stream().filter(permission - permission.getPermission() ! null).map(permission - new SimpleGrantedAuthority(permission.getPermission())).collect(Collectors.toList());}Overridepublic String getPassword() {return user.getPassword();}Overridepublic String getUsername() {return user.getUsername();}Overridepublic boolean isAccountNonExpired() {return true;}Overridepublic boolean isAccountNonLocked() {return true;}Overridepublic boolean isCredentialsNonExpired() {return true;}Overridepublic boolean isEnabled() {return true;} } 5.登录设置 Overridepublic String login(SysUser sysUser) {String token null;//密码需要客户端加密后传递try {UserDetails userDetails sysUserService.loadUserByUsername(sysUser.getUsername());if(!passwordEncoder.matches(sysUser.getPassword(),userDetails.getPassword())){throw new BadCredentialsException(密码不正确);}UsernamePasswordAuthenticationToken authentication new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());SecurityContextHolder.getContext().setAuthentication(authentication);token jwtTokenUtil.generateToken(userDetails);String key login: sysUser.getUsername();//设置redisredisHelper.setCacheObject(key,userDetails);//insertLoginLog(username);} catch (AuthenticationException e) {LOGGER.warn(登录异常:{}, e.getMessage());}return token;}Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {SysUser sysUser sysUserMapper.selectOne(new QueryWrapperSysUser().eq(username, username));ListSysPermission permissionsByUser sysUserRoleMapper.findPermissionsByUser(sysUser.getUserId());sysUser.setPassword(new BCryptPasswordEncoder().encode(sysUser.getPassword()));// 将系统的用户信息和权限信息封装成UserDetailsUserDetails userDetail new LoginUser(sysUser, permissionsByUser);return userDetail;} 6.JWT校验 Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {String authHeader request.getHeader(this.tokenHeader);if (authHeader ! null authHeader.startsWith(this.tokenHead)) {String authToken authHeader.substring(this.tokenHead.length());// The part after Bearer String username jwtTokenUtil.getUserNameFromToken(authToken.trim());LOGGER.info(checking username:{}, username);if (username ! null SecurityContextHolder.getContext().getAuthentication() null) {//从redis中获取userDetailsString redisKey login: username;UserDetails userDetails redisHelper.getCacheObject(redisKey);if(Objects.isNull(userDetails)){throw new RuntimeException(用户未登录);}if (jwtTokenUtil.validateToken(authToken, userDetails)) {//存入SecurityContextHolder//TODO 获取权限信息封装到Authentication中UsernamePasswordAuthenticationToken authentication new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));LOGGER.info(authenticated user:{}, username);SecurityContextHolder.getContext().setAuthentication(authentication);}}}//放行filterChain.doFilter(request, response);} 7.fastjson版本 !--fastjson依赖--!--第一个版本--dependencygroupIdcom.alibaba/groupIdartifactIdfastjson/artifactIdversion1.2.47/version/dependency!--第二个版本--dependencygroupIdcom.alibaba/groupIdartifactIdfastjson/artifactIdversion2.0.22/version/dependency 上面的代码中先根据用户名获取用户对应的用户信息和权限信息然后构建SpringSecurity的UserDetails对象用户登录的时候将这个UserDetails对象放入redis中后续校验请求携带的token与redis中的信息是否一致。 二、异常信息 1.版本一报错信息 需要说明的是在redis系列化时是正常的对应的值也成功设置近缓存了但是在JWT校验阶段执行UserDetails userDetails redisHelper.getCacheObject(redisKey);时出现异常反序列化失败。 针对这个问题首先上面的代码逻辑是没有问题的但是与fastjson反序列化不兼容导致的问题。 根据异常信息提示设置属性authorities错误猜想下是因为LoginUser中没有authorities属性但也说不过去同样没有属性username和password怎么不会报错 带着这个疑问我们先给将LoginUser代码改为下面这种形式。 Data public class LoginUser implements UserDetails {private static final long serialVersionUID 1L;private SysUser user;private ListSysPermission permissionList;private ListGrantedAuthority authorities;public LoginUser() {}public LoginUser(SysUser user, ListSysPermission permissionList) {this(user,permissionList,null);}/*** 针对fastJson中redis反序列化报错的改进* org.springframework.data.redis.serializer.SerializationException:* Could not deserialize: set authorities error; nested exception is com.alibaba.fastjson.JSONException: set authorities error** param user* param permissionList* param authorities*/public LoginUser(SysUser user, ListSysPermission permissionList, ListGrantedAuthority authorities) {//返回当前用户的权限ListGrantedAuthority authoritieList permissionList.stream().filter(permission - permission.getPermission() ! null).map(permission - new SimpleGrantedAuthority(permission.getPermission())).collect(Collectors.toList());this.user user;this.permissionList permissionList;this.authorities authoritieList;}Overridepublic Collection? extends GrantedAuthority getAuthorities() {return this.authorities;}Overridepublic String getPassword() {return user.getPassword();}Overridepublic String getUsername() {return user.getUsername();}Overridepublic boolean isAccountNonExpired() {return true;}Overridepublic boolean isAccountNonLocked() {return true;}Overridepublic boolean isCredentialsNonExpired() {return true;}Overridepublic boolean isEnabled() {return true;} } 发现这里改完之后是可以正常运行的。 而且发现当我们给getAuthorities()赋简单的值的时候不会出现这个问题。 Overridepublic Collection? extends GrantedAuthority getAuthorities() {ListGrantedAuthority authoritieList new ArrayList();authoritieList.add(new SimpleGrantedAuthority(ROLE_ADMIN));return authoritieList;} 而且我们在构造函数中提前将权限列表加载出来赋值给一个属性属性不一定非得名为authorities如属性名为authoritiesList。然后返回这个属性也不会报错。 Overridepublic Collection? extends GrantedAuthority getAuthorities() {return this.authoritieList;} 通过上面两个测试可以猜测下如果构造函数中提前将比较复杂的实现暴露了反系列化也不会报错。可能出现异常的原因fastjson是对不确定结果无法反系列化如果是简单的结果或在构造器中就已经知道了确定结果就不会出现反序列化的异常。  2.版本二报错信息 在使用fastJson 2.x版本的时候同时需要对redis配置类做如下修改。 BeanSuppressWarnings(value { unchecked, rawtypes })public RedisTemplateObject, Object redisTemplate(RedisConnectionFactory connectionFactory){RedisTemplateObject, Object template new RedisTemplate();template.setConnectionFactory(connectionFactory);/*java.lang.ClassCastException:* com.alibaba.fastjson.JSONObject cannot be cast to org.springframework.security.core.userdetails.UserDetails* */String[] acceptNames {org.springframework.security.core.authority.SimpleGrantedAuthority};GenericFastJsonRedisSerializer serializer new GenericFastJsonRedisSerializer(acceptNames);// 使用StringRedisSerializer来序列化和反序列化redis的key值template.setKeySerializer(new StringRedisSerializer());template.setValueSerializer(serializer);// Hash的key也采用StringRedisSerializer的序列化方式template.setHashKeySerializer(new StringRedisSerializer());template.setHashValueSerializer(serializer);template.afterPropertiesSet();return template;} 修改完成之后还是会出现设置属性authorities错误同样需要对LoginUser做上述修改。 3.发现FastJson反系列的一般问题 正如上面所说的同样没有属性username和password怎么不会报错于是做了一系列测试。发现了在低版本的fastJson中对应集合类型接口方法中包含较复杂的实现不是直接显示赋值反序化可能要求必须有对应的属性。 定义了一个有不同返回值类型的几种方法来测试。 public interface CrazyDetails {ListString getApps();User getUser();String getName();String[] getNodes();CollectionString getTests();ListUser getUsers(); } 定义一个实现类 Data NoArgsConstructor AllArgsConstructor public class MosulApp implements CrazyDetails{Overridepublic User getUser() {return new User(this.appInfo.name);}private AppInfo appInfo;Overridepublic ListUser getUsers() {ListUser userList new ArrayList();for(int i 0; i this.appInfo.name.length(); i ) {User user1 new User( i);userList.add(user1);}return userList;}Overridepublic String[] getNodes() {String[] strings new String[2];strings new String[]{this.appInfo.name,this.appInfo.details};return strings;}/*private ListString apps;*///报错添加需要private ListString testsOverridepublic CollectionString getTests() {ListString list Arrays.asList(appInfo.name);return list;}Overridepublic ListString getApps() {ListString objects new ArrayList();for(int i 0; i this.appInfo.name.length(); i ) {objects.add(tt i);}return objects;}Overridepublic String getName() {return this.appInfo.name;}} 在测试发现fastJson 1.x版本对于Arrays.asList(appInfo.name);反序列化失败fastJson 2.x版本则可以反序列化成功但对于UserDetails中Collection? extends GrantedAuthority getAuthorities()中如果有比较复杂的实现fastJson 2.x版本反序列化还是会失败。所以为了保险起见最后在自定义的UserDetails中添加authorities属性除了这种方法能外应该也跟自定义的序列化器相关设置有关需要进行探索。 三、Redis和SpringSecutiry相关配置 基于上述测试最终fastJson选用2.0.22版本最后将redis配置类和SpringSecutiry中UserDetails实现类修改为如下所示。 1.redis配置类 Configuration public class RedisConfig {/*** 指定特定的连接工厂* return*//*Beanpublic RedisConnectionFactory redisConnectionFactory() {return new LettuceConnectionFactory();}*/BeanSuppressWarnings(value { unchecked, rawtypes })public RedisTemplateObject, Object redisTemplate(RedisConnectionFactory connectionFactory){RedisTemplateObject, Object template new RedisTemplate();template.setConnectionFactory(connectionFactory);/* FastJsonRedisSerializer serializer new FastJsonRedisSerializer(Object.class);*//*解决java.lang.ClassCastException:* com.alibaba.fastjson.JSONObject cannot be cast to org.springframework.security.core.userdetails.UserDetails* */String[] acceptNames {org.springframework.security.core.authority.SimpleGrantedAuthority};GenericFastJsonRedisSerializer serializer new GenericFastJsonRedisSerializer(acceptNames);// 使用StringRedisSerializer来序列化和反序列化redis的key值template.setKeySerializer(new StringRedisSerializer());template.setValueSerializer(serializer);// Hash的key也采用StringRedisSerializer的序列化方式template.setHashKeySerializer(new StringRedisSerializer());template.setHashValueSerializer(serializer);template.afterPropertiesSet();return template;} } 2.LoginUser类 Data public class LoginUser implements UserDetails {private static final long serialVersionUID 1L;// 用户信息private SysUser user;// 用户权限列表private ListSysPermission permissionList;// SpringSecurity对应的权限信息private ListGrantedAuthority authorities;public LoginUser() {}public LoginUser(SysUser user, ListSysPermission permissionList) {this(user,permissionList,null);}/*** 针对fastJson中redis反序列化报错的改进* org.springframework.data.redis.serializer.SerializationException:* Could not deserialize: set authorities error; nested exception is com.alibaba.fastjson.JSONException: set authorities error** param user* param permissionList* param authorities*/public LoginUser(SysUser user, ListSysPermission permissionList, ListGrantedAuthority authorities) {//返回当前用户的权限ListGrantedAuthority authoritieList permissionList.stream().filter(permission - permission.getPermission() ! null).map(permission - new SimpleGrantedAuthority(permission.getPermission())).collect(Collectors.toList());this.user user;this.permissionList permissionList;this.authorities authoritieList;}Overridepublic Collection? extends GrantedAuthority getAuthorities() {return this.authorities;}Overridepublic String getPassword() {return user.getPassword();}Overridepublic String getUsername() {return user.getUsername();}Overridepublic boolean isAccountNonExpired() {return true;}Overridepublic boolean isAccountNonLocked() {return true;}Overridepublic boolean isCredentialsNonExpired() {return true;}Overridepublic boolean isEnabled() {return true;} }
http://www.hkea.cn/news/14320022/

相关文章:

  • 食品网站建设建议凡度网络北京网站建设公司
  • 做网站需要提供些什么页面四川省建设建设监理协会网站
  • app网站开发长沙比亚迪新能源车型及价格
  • 哈巴河网站制作网页制作网站首页设计
  • 电子产品商务网站模板简单手工
  • 微网站建设加盟多页网站制作
  • 北京网站开发公司电话外链网址
  • 孝义网站建设长沙网站排名系统
  • 个人主页建站百度手机助手安卓版下载
  • 用户体验好的网站济南槐荫区做网站的
  • 做网站的前景网站建设面试题
  • 一流的聊城做网站费用互联网推广渠道
  • app优化网站外包兼职做图的网站
  • 企业网站能提供哪些服务汉中杨海明
  • 做美食视频网站有哪些商标购买在哪个平台好
  • seo的工作流程企业网站seo数据
  • 网站建设中主机放在哪里网站及推广
  • 不会写代码如何做网站百度关键字优化
  • 网站的推广等内容都江堰网站建设
  • 沈阳专门代做网站的产品设计方案3000字
  • 网站怎么备案在哪里公司内部管理系统软件
  • 哪些网站做商标注册陕西省住房建设厅官方网站
  • wordpress 焦点图免费网站seo排名优化
  • 珠海网站制作费用wordpress安装云
  • asp.net 网站开发架构电影网站logo设计
  • 网站与新媒体建设测评方案外贸接单网站
  • 门户网站建设询价函东莞厚街创新科技职业学院
  • 网站推广软件费用是多少宁波微网站建设
  • 中国那个公司的网站做的最好看受欢迎的福州网站建设
  • 广州网站建设类岗位wordpress素材网主题