Issue
I wrote my implementation of UserDetails in order to change the login and user roles. With the login, everything turned out to be quite simple, but I had problems with the roles. I don't understand what I need to do in order to change the default CUSTOMER role to another SELLER role
@ToString
public class CustomUserDetails implements UserDetails {
@ToString.Exclude
private Account account;
private final long serialVersionUID = 1L;
public CustomUserDetails(Account account) {
this.account = account;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
List<GrantedAuthority> authorities = new ArrayList<>();
authorities.add(new SimpleGrantedAuthority("ROLE_" + this.account.getRole().getAuthority()));
return authorities;
}
public void setRole(Role role) {
this.account.setRole(role);
}
@Override
public String getPassword() {
return this.account.getPassword();
}
@Override
public String getUsername() {
return this.account.getLogin();
}
public void setUsername(String username) {
this.account.setLogin(username);
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
Solution
Perhaps I should have been more specific about my question. But. I found a solution to this problem for myself. Maybe my method will help someone.
My CustomUserDetailsService:
@Service("userDetailsService")
public class CustomUserDetailsService implements UserDetailsService {
@Autowired
private AccountRepository accountRepository;
@Override
public UserDetails loadUserByUsername(String login) throws UsernameNotFoundException {
Account account = accountRepository.findByLogin(login);
if (account == null) {
throw new UsernameNotFoundException(login);
}
return new CustomUserDetails(account, mapRolesToAuthority(account.getRole()));
}
private Collection<? extends GrantedAuthority> mapRolesToAuthority(Role role) {
List<GrantedAuthority> authorities = new ArrayList<>();
authorities.add(new SimpleGrantedAuthority("ROLE_" + role.getAuthority()));
authorities.add(new SimpleGrantedAuthority(role.getAuthority()));
return authorities;
}
}
My CustomUserDetails:
@ToString
public class CustomUserDetails implements UserDetails {
@ToString.Exclude
private Account account;
private Collection<? extends GrantedAuthority> authorities;
private final long serialVersionUID = 1L;
public CustomUserDetails(Account account, Collection<? extends GrantedAuthority> authorities) {
this.account = account;
this.authorities = authorities;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return authorities;
}
public void setAuthorities(Collection<? extends GrantedAuthority> authorities) {
this.authorities = authorities;
}
@Override
public String getPassword() {
return this.account.getPassword();
}
@Override
public String getUsername() {
return this.account.getLogin();
}
public void setUsername(String username) {
this.account.setLogin(username);
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
Method in the controller that changes data in the user session (needs refactoring):
@PostMapping("/trade")
public String updateAccountRole(Principal principal) {
Account account = accountRepository.findByLogin(principal.getName());
account.setRole(Role.SELLER);
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
CustomUserDetails userDetails = (CustomUserDetails) authentication.getPrincipal();
List<GrantedAuthority> authorities = new ArrayList<>();
authorities.add(new SimpleGrantedAuthority("ROLE_" + account.getRole().getAuthority()));
authorities.add(new SimpleGrantedAuthority(account.getRole().getAuthority()));
userDetails.setAuthorities(authorities);
System.out.println("BEFORE -> " + SecurityContextHolder.getContext().getAuthentication());
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
SecurityContextHolder.getContext().getAuthentication().getPrincipal(),
SecurityContextHolder.getContext().getAuthentication().getCredentials(),
userDetails.getAuthorities()
);
token.setDetails(SecurityContextHolder.getContext().getAuthentication().getDetails());
SecurityContextHolder.getContext().setAuthentication(token);
System.out.println("AFTER -> " + SecurityContextHolder.getContext().getAuthentication());
accountRepository.save(account);
return "redirect:/";
}
Thus, I managed to achieve a dynamic change of roles for the user. If you have any suggestions on how my method can be improved, I'd love to hear it.
Answered By - Mark
Answer Checked By - Terry (JavaFixing Volunteer)