Reputation: 1474
I have an application that is configured with spring security.
Everything is working as well.
The UserDetailService is:
@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;
}
}
After that I was forced to config spring session over this configuration for saving the context of spring security into Redis.
There exists a problem in UserDetailService.
UserDetailService have two autowired filed as shown above are:
@Autowired
private IUserDetailRepository iUserDetailRepository;
@Autowired
private IUserRoleRepository iUserRoleRepository;
This two autowired field are for getting User and User's roles information from DB.
It is interesting here that when I comment this two autowired like this:
//@Autowired
private IUserDetailRepository iUserDetailRepository;
//@Autowired
private IUserRoleRepository iUserRoleRepository;
and fill manually user and user's role.Spring session is working as well but when this two @Autowired
exist in the class the below exception is raised:
Caused by: org.springframework.core.serializer.support.SerializationFailedException: Failed to serialize object using DefaultSerializer; nested exception is java.io.NotSerializableException: org.springframework.dao.support.PersistenceExceptionTranslationInterceptor at 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 common frames omitted Caused by: java.io.NotSerializableException: org.springframework.dao.support.PersistenceExceptionTranslationInterceptor at 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]
Everybody know that what is happen?
I do not understand what is happen.
I do not know there is what key for searching in google
I want to know what is happen between spring session and spring security and how to solve it.
Thanks for your helping
Upvotes: 2
Views: 2024
Reputation: 125242
This has actually nothing to do with those dependencies, it is due to the fact that you are using an (non static
) inner class. You should either use an embedded static
class or simply use the regular User
class from Spring Security. (More on inner, (non) static embedded classes are found in this answer.
In short due to the fact of you using an inner classes it requires an instance of the outer class to exist. Now when serializing the UserDetails
it will also try to serialize the outer class.
The simplest solution is to rewrite your code and use the Spring Security provided User
class (assuming you are using Spring Security 4.2 you can use the 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();
}
If you are on Spring Security before 4.2 you can simply construct a User
object using the constructor.
return new User(user.getUsername(), user.getPassword(), user.getEnable(), true, true, true, <convert-roles-to-SimpleGrantedAuthoritu>);
When return a concrete class it doesn't require an instance of the outer class (as it isn't an inner class) and it will not try to serialize it. It will only serialize the User
and nothing else.
Upvotes: 3
Reputation: 1474
I solve my problem with this solution:
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;
}
Upvotes: 0