Using Spring Boot 1.3.1, I am having problems with @AuthenticationPrincipal
.
This is my controller:
@RestController
@RequestMapping("/api/user")
public class UserController {
@RequestMapping("/")
public UserDto user(@AuthenticationPrincipal(errorOnInvalidType = true) User user) {
return UserDto.fromUser(user);
}
}
This is my custom User class:
@Entity()
@Table(name = "app_user")
public class User extends AbstractEntity<UserId> implements Serializable {
// ------------------------------ FIELDS ------------------------------
@NotNull
@Column(unique = true)
@Pattern(regexp = "[a-zA-Z_\\-\\.0-9]+")
@Size(min = 1, max = 20)
private String username;
private String password;
@Column(unique = true)
@Email
private String emailAddress;
@Enumerated(EnumType.STRING)
@NotNull
private UserRole role;
}
I also created a class to confirm to the UserDetails
interface of Spring Security:
public class CustomUserDetails extends User implements UserDetails {
public CustomUserDetails(User user) {
super(user);
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return Sets.newHashSet(new SimpleGrantedAuthority("ROLE_" + getRole().name()));
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
Then in my UserDetailsService
:
@Override
public CustomUserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
com.company.app.domain.account.User user = userRepository.findByUsername(username);
if (user != null) {
return new CustomUserDetails(user);
} else {
throw new UsernameNotFoundException(format("User %s does not exist!", username));
}
}
I have an integration test that works perfectly. However, running the application itself (from IntelliJ IDEA), does not work. I get an exception:
"CustomUserDetails{id=UserId{id=401868de-99ff-4bae-bcb6-225e3062ed33}} is not assignable to class com.company.app.domain.account.User"
But this is not true, since CustomUserDetails
is a subclass of my custom User
class.
Checking with the debugger, I see that this code in AuthenticationPrincipalArgumentResolver
fails:
if (principal != null
&& !parameter.getParameterType().isAssignableFrom(principal.getClass())) {
The classloader of parameter.getParameterType()
is an instance of RestartClassloader
, while principal.getClass()
has a classloader that is an instance of Launcher$AppClassLoader
.
Is this a bug in Spring Boot or Spring Security or am I doing something wrong?
UPDATE:
I can confirm that disabling devtools of Spring Boot makes it work:
public static void main(String[] args) {
System.setProperty("spring.devtools.restart.enabled", "false");
SpringApplication.run(MyApplication.class, args);
}