春天的依赖注入和序列化对象

时间:2017-06-08 06:20:20

标签: serialization spring-boot spring-security dependency-injection spring-session

我有一个配置了弹簧安全性的应用程序 一切都在运作。
UserDetailService是:

@Service(value = "userDetail")
public class UserDetailServiceImpl implements UserDetailsService, Serializable {
    private static final long serialVersionUID = 3487495895819392L;

    @Autowired
    private IUserDetailRepository iUserDetailRepository;

    @Autowired
    private IUserRoleRepository iUserRoleRepository;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = iUserDetailRepository.loadUserByUsername(username);
        List<UserRole> roles = iUserRoleRepository.getAllRoleByUserName(username);
        UserDetails u = new UserDetails() {

            @Override
            public boolean isEnabled() {
                // return user.getEnable();
                return true;
            }

            @Override
            public boolean isCredentialsNonExpired() {
                return true;
            }

            @Override
            public boolean isAccountNonLocked() {
                return true;
            }

            @Override
            public boolean isAccountNonExpired() {
                return true;
            }

            @Override
            public String getUsername() {
                // return user.getUsername();
                return "reyhane";
            }

            @Override
            public String getPassword() {
                // return user.getPassword();
                return "reyhane";
            }

            @Override
            public Collection<? extends GrantedAuthority> getAuthorities() {
                Collection<GrantedAuthority> authorities = new ArrayList<>();
                SimpleGrantedAuthority authority = new SimpleGrantedAuthority("ADMIN");
                authorities.add(authority);

                return authorities;

            }
        };
        return u;
    }

}

之后我被迫在这个配置上配置spring会话,以便将Spring安全的上下文保存到Redis中 UserDetailService中存在问题 UserDetailService有两个自动装配的文件,如上所示:

@Autowired
private IUserDetailRepository iUserDetailRepository;

@Autowired
private IUserRoleRepository iUserRoleRepository;

这两个自动连接字段用于从DB获取用户和用户的角色信息 这里有趣的是,当我评论这两个自动装配时:

//@Autowired
private IUserDetailRepository iUserDetailRepository;

//@Autowired
private IUserRoleRepository iUserRoleRepository;

并手动填写用户和用户的角色.Spring会话也正常工作但是当这两个@Autowired存在于类中时,会引发以下异常:

  

引起:   org.springframework.core.serializer.support.SerializationFailedException:   无法使用DefaultSerializer序列化对象;嵌套异常   是java.io.NotSerializableException:   org.springframework.dao.support.PersistenceExceptionTranslationInterceptor   在   org.springframework.core.serializer.support.SerializingConverter.convert(SerializingConverter.java:68)   〜[spring-core-4.3.2.RELEASE.jar:4.3.2.RELEASE] at   org.springframework.core.serializer.support.SerializingConverter.convert(SerializingConverter.java:35)   〜[spring-core-4.3.2.RELEASE.jar:4.3.2.RELEASE] at   org.springframework.data.redis.serializer.JdkSerializationRedisSerializer.serialize(JdkSerializationRedisSerializer.java:90)   〜[spring-data-redis-1.7.2.RELEASE.jar:na] ...省略了35个常用帧   引起:java.io.NotSerializableException:   org.springframework.dao.support.PersistenceExceptionTranslationInterceptor   在   java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)   〜[na:1.8.0_111] at   java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548)   〜[NA:1.8.0_111]

每个人都知道发生了什么? 我不明白发生了什么 我不知道谷歌搜索有什么关键 我想知道春季会议和春季安全之间会发生什么,以及如何解决它 谢谢你的帮助

2 个答案:

答案 0 :(得分:3)

这实际上与这些依赖关系无关,这是因为您正在使用(非static)内部类。您应该使用嵌入式static类,或者只使用Spring Security中的常规User类。 (有关内部,(非)静态嵌入类的更多信息,请参见this answer

简而言之,由于您使用内部类的事实,它需要存在外部类的实例。现在,当序列化UserDetails时,它也会尝试序列化外部类。

最简单的解决方案是重写代码并使用Spring Security提供的User类(假设您使用的是Spring Security 4.2,您可以使用UserBuilder)。

@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
    User user = iUserDetailRepository.loadUserByUsername(username);
    List<UserRole> roles = iUserRoleRepository.getAllRoleByUserName(username);

    return User.withUsername(user.getUsername())
                        .password(user.getPassword())
                        .disabled(!user.getEnable())
                        .roles(roles.stream().map(<convert-to-SimpleGrantedAuthority>).collect(Collectors.toList()))
                        .build();
}

如果您在4.2之前使用Spring Security,则只需使用构造函数构造User对象即可。

return new User(user.getUsername(), user.getPassword(), user.getEnable(), true, true, true, <convert-roles-to-SimpleGrantedAuthoritu>);

当返回一个具体类时,它不需要外部类的实例(因为它不是内部类),并且它不会尝试序列化它。它只会序列化User而不会其他任何内容。

答案 1 :(得分:0)

我用这个解决方案解决了我的问题:

private static IUserDetailRepository userDetailRepository;

private static IUserRoleRepository userRoleRepository;

    @Autowired
    public void setUserDetailRepository(IUserDetailRepository userDetailRepository) {
        UserDetailServiceImpl.userDetailRepository = userDetailRepository;
    }

   @Autowired
   public void setUserRoleRepository(IUserRoleRepository userRoleRepository) {
       UserDetailServiceImpl.userRoleRepository = userRoleRepository;
    }