Внедрение зависимостей и объект сериализации весной

У меня есть приложение, настроенное с помощью Spring Security.
Все также работает.
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;

Эти два автоматически подключаемых поля предназначены для получения информации о пользователях и ролях пользователей из БД.
Интересно, что, когда я комментирую эти два автоматически подключаемых поля следующим образом:

//@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] в 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] в java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java: 1548) ~[на:1.8.0_111]

Все знают, что происходит?
Я не понимаю, что происходит.
Я не знаю, какой ключ для поиска в гугле
Я хочу знать, что происходит между весенней сессией и Spring Security и как ее решить.
Спасибо за помощь


person reza ramezani matin    schedule 08.06.2017    source источник
comment
Основная проблема заключается в том, что вы используете анонимный внутренний класс в своем методе. Не делайте этого, просто создайте новый User вместо нового UserDetails, и вам не нужны никакие хаки.   -  person M. Deinum    schedule 08.06.2017
comment
Пожалуйста, объясните подробнее   -  person reza ramezani matin    schedule 08.06.2017


Ответы (2)


На самом деле это не имеет ничего общего с этими зависимостями, это связано с тем, что вы используете внутренний класс (не static). Вы должны либо использовать встроенный класс static, либо просто использовать обычный класс User из Spring Security. (Подробнее о внутренних (не)статических встроенных классах можно найти в этом ответе.

Короче говоря, из-за того, что вы используете внутренние классы, для существования требуется экземпляр внешнего класса. Теперь при сериализации 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();
}

Если вы используете Spring Security до версии 4.2, вы можете просто создать объект User с помощью конструктора.

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

Когда возвращается конкретный класс, ему не требуется экземпляр внешнего класса (поскольку он не является внутренним классом), и он не будет пытаться его сериализовать. Он будет сериализовать только User и ничего больше.

person M. Deinum    schedule 08.06.2017
comment
Большое спасибо за ваш лучший ответ - person reza ramezani matin; 08.06.2017

Я решаю свою проблему с помощью этого решения:

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;
    }
person reza ramezani matin    schedule 08.06.2017
comment
См. Комментарий, который на самом деле не решение, а хак, чтобы заставить его работать. - person M. Deinum; 08.06.2017
comment
У вас есть решение для этого? - person reza ramezani matin; 08.06.2017
comment
Я уже дал вам это, не используйте анонимный внутренний класс. Используйте Spring Security User и заполните свойства соответствующим образом. - person M. Deinum; 08.06.2017