Nicholas
Nicholas

Reputation: 105

ClassCastException - Spring Security With User

I'm currently making an E-Commerce application and I'm trying to add "Add To Cart" functionality. I haven't yet worked with httprequests, so everyone has to login before accessing the website.

When a user logs in, goes onto the home page and tries to add a product to cart, it will send a post request to add that product.

    @PostMapping("/cart/{id}")
public String addProduct(@PathVariable Long id, @ModelAttribute("cartItem") CartItems cartItem, Model model) {
    Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
    User user = ((User) principal);

        Optional<Product> product = productService.findById(id);
        cartItem.setProduct(product.get());
        cartItem.setPrice(cartItem.getQuantity() * cartItem.getProduct().getPrice());

        user.getCart().getCartItems().add(cartItem);

        return "redirect:/cart";
   }

User Class:

@Entity
@EntityListeners(AuditingEntityListener.class)
@Table(name = "users")
public class User implements Serializable, UserDetails 
{

private static final long serialVersionUID = -8903772563656397127L;

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "user_id")
private Long id;

@Column(name = "username")
private String username;

@Column(name = "email")
private String email;

@Column(name = "password")
private String password;

@Column(name = "first_name")
private String firstName;

@Column(name = "last_name")
private String lastName;

@OneToOne(mappedBy = "user")
private Cart cart;

@Column(name = "address")
private String address;

USER DETAILS:

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

    Set<GrantedAuthority> grantedAuthorities = new HashSet<>();
    grantedAuthorities.add(new SimpleGrantedAuthority("UNDEFINED"));

    return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), grantedAuthorities);
}

The problem is casting the User class to Object principal from user details. I am getting the following error:

java.lang.ClassCastException: class org.springframework.security.core.userdetails.User cannot be cast to class com.nickjojo.ecomapp.entity.User (org.springframework.security.core.userdetails.User and com.nickjojo.ecomapp.entity.User are in unnamed module of loader 'app')

Upvotes: 0

Views: 4627

Answers (2)

Marco Behler
Marco Behler

Reputation: 3724

There's a couple of things I would improve here:

  1. Your User class already implements UserDetails, so no need to convert it to a org.springframework.User in your UserDetailsService.loadUserByUsername. Simply return it.

  2. Instead of going through the SecurityContext, you can then simply go with the @AuthenticationPrincipal annotation like so (note, it will be null if the user is not logged in):

@PostMapping("/cart/{id}")

public String addProduct(... @AuthenticationPrincipal user) {
// ...
}

Upvotes: 1

Nicholas
Nicholas

Reputation: 105

I found the answer. I was casting User to the principle object, but instead I casted UserDetails to the object (they can be casted together), then got the object's username as specified as one of the fields when returning a UserDetails object in the UserDetailsService class. I then used that username to find the user through my service.

        Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
    String username = ((UserDetails) principal).getUsername();
    User user = userService.findByUsername(username);

Upvotes: 1

Related Questions