How to differ two entities of UserDetails?

41 Views Asked by At

I've got two entites - User and Manager.

MANAGER

public class Manager extends BaseEntity implements UserDetails {

    private String email;
    private String password;

    private String firstName;
    private String lastName;

    private String position;
    private String avatar;

    @ManyToMany(fetch = FetchType.EAGER)
    @JoinTable(
            name = "manager_authorities",
            joinColumns = @JoinColumn(name = "manager_id"),
            inverseJoinColumns = @JoinColumn(name = "authority_id"))
    private List<Authority> authorities;

    private boolean isEnabled;

    @Enumerated(EnumType.STRING)
    private AdminType adminType;

    @OneToMany(mappedBy = "manager")
    private List<EventRequest> eventRequests;

    @Override
    public String getUsername() {
        return email;
    }

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

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

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

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Manager manager = (Manager) o;
        return Objects.equals(email, manager.email) && Objects.equals(password, manager.password);
    }

    @Override
    public int hashCode() {
        return Objects.hash(email, password);}

USER

@Entity
@Builder
@Getter @Setter
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "users")
public class User extends BaseEntity implements UserDetails {

    private String email;
    private String password;

    private String firstName;
    private String lastName;

    @ManyToMany(fetch = FetchType.EAGER)
    @JoinTable(
            name = "user_authorities",
            joinColumns = @JoinColumn(name = "user_id"),
            inverseJoinColumns = @JoinColumn(name = "authority_id"))
    private List<Authority> authorities;

    private boolean isEnabled;

    @Enumerated(EnumType.STRING)
    private UserType userType;

    @Override
    public String getUsername() {
        return email;
    }

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

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

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

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        User user = (User) o;
        return Objects.equals(email, user.email) && Objects.equals(password, user.password);
    }

    @Override
    public int hashCode() {
        return Objects.hash(email, password);
    }
}

Now i don't know to differ them from each other, because they both go throught the same authentication method:


@Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        String username = authentication.getName();
        String password = authentication.getCredentials().toString();

        try {
            UserDetails userDetails = userService.loadUserByUsername(username);

            if (userDetails != null) {
                if (userDetails instanceof Manager) { //this condition always gives false
                    Manager manager = (Manager) userDetails;
                    if (manager.getEmail().equals(username) && encoder.matches(password, manager.getPassword())) {
                        return new UsernamePasswordAuthenticationToken(manager, null, manager.getAuthorities());
                    }
                } else {
                    User user = (User) userDetails;
                    if (user.getEmail().equals(username) && user.getPassword().equals(password)) {
                        return new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities());
                    }
                }
            }
        } catch (Exception e) {
            throw new UsernameNotFoundException("Пользователь с именем пользователя " + username + " не найден", e);
        }
        return null;
    }

Both of their interfaces implement UserDetailsService

}

I tried to get instanceof of class, but IDEA tells that these conditions always gives false value. I don't know what should i get from credetials to diifer them

1

There are 1 best solutions below

0
tdonuk On

I suppose UserDetails here is Spring security's UserDetails. Instead of directly implementing Spring's UserDetails interface from your entities, you can create a seperate class like below:

public class CustomUserDetails implements UserDetails {

private User user;

public CustomUserDetails(User user) {
    this.user = user;
}

public User getUser() {
    return this.user;
}

@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
    List<GrantedAuthority> list = new ArrayList<>();

    list.add(new SimpleGrantedAuthority(user.getRole().getRoleText().toUpperCase()));

    return list;
}
... other methods
}

then you can write a seperate service for UserDetails like:

public class UserDetailsServiceImpl implements UserDetailsService {

@Autowired
UserService userService;

@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
    User user = (User) userService.getUserByEmail(username);

    if(user == null) {
        throw new UsernameNotFoundException("Could not find user");
    }

    return new CustomUserDetails(user);
}
}

Finally, update your UserService class to make it returns BaseEntity (Or another superclass between User and BaseEntity?) instead of UserDetails.

Now since it is returning BaseEntity (?), you can cast it to User or Manager as you wish.

Also instead of managing this logic like that using seperate classes for manager and user, You can add a field like role to User entity. by doing that, you need just User entity and you can differ Manager and user by checking role field.

*note: code samples are taken from another project to provide examples. i hope it helps