In this article, I will share how to retrieve a UserDetails object that represents the currently logged-in user in a Spring Boot application with Spring Security. Then you can display email, username, first name, last name, full name, assigned roles, any user’s information in the view (using Thymeleaf); and also get the UserDetails object in a handler method of a Spring controller.

Suppose that we have the entity class User as follows:

package net.codejava;

import java.util.*;
import javax.persistence.*;

@Entity
@Table(name = "users")
public class User {
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Integer id;
	
	private String email;
	
	private String password;
	
	@Column(name = "full_name")
	private String fullName;
	
	private boolean enabled;
	
	@ManyToMany(cascade = CascadeType.PERSIST, fetch = FetchType.EAGER)
	@JoinTable(
			name = "users_roles",
			joinColumns = @JoinColumn(name = "user_id"),
			inverseJoinColumns = @JoinColumn(name = "role_id")
			)
	private Set<Role> roles = new HashSet<>();

	// constructors, getters and setters are not shown for brevity
}

And the entity class Role as below:

package net.codejava;

import javax.persistence.*;

@Entity
@Table(name = "roles")
public class Role {
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Integer id;
	
	private String name;
	
	private String description;

	// constructors, getters and setters are not shown for brevity	
}

To use Spring Security for authentication and authorization, we code a class that implements the UserDetails interface as follows:

package net.codejava

import java.util.*;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

public class ShopmeUserDetails implements UserDetails {
	private User user;
	
	public ShopmeUserDetails(User user) {
		this.user = user;
	}

	@Override
	public Collection<? extends GrantedAuthority> getAuthorities() {
		Set<Role> roles = user.getRoles();
		List<SimpleGrantedAuthority> authorities = new ArrayList<>();
		
		for (Role role : roles) {
			authorities.add(new SimpleGrantedAuthority(role.getName()));
		}
		return authorities;
	}

	@Override
	public String getPassword() {
		return user.getPassword();
	}

	@Override
	public String getUsername() {
		return user.getEmail();
	}

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

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

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

	@Override
	public boolean isEnabled() {
		return user.isEnabled();
	}
}

You can see this UserDetails class wraps the User entity class.

And code a class that implements the UserDetailsService, which overrides the loadUserByUsername() method for authentication as below:

package net.codejava;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.*;

public class ShopmeUserDetailsService implements UserDetailsService {

	@Autowired
	private UserRepository userRepository; 
	
	@Override
	public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
		User user = userRepository.getUserByEmail(email);
		if (user == null) {
			throw new UsernameNotFoundException("Could not find user with that email");
		}
		
		return new ShopmeUserDetails(user);
	}
}

As you can see, when a user has logged in successfully, a ShopmeUserDetails object is returned to Spring Security, and it will be set as the principal object in the security context.

So when we retrieve the object that represents the currently logged-in user in the application, we actually get the object returned by the loadUserByUsername() method, which wraps an object of the User entity class.

 

1. Display the default username

To show the default username of the currently logged-in user in a view template using Thymeleaf, we can print the value of remoteUser object associated with the current request:

<span>[[${#request.remoteUser}]]</span>

Or using Thymeleaf Extras for Spring Security:

<span sec:authentication="name">Username</span>

However, this way always prints the value returned from the getUsername() method in the UserDetails class (ShopmeUserDetails in this article).

What if we want to display another attribute of the user, e.g. first name, last name or fullname?

We can change the value returned by the getUsername() method, but it will break other functions that depend on the username, e.g. Remember me feature provided by Spring Security.

Read the next section to know how.

 

2. Display any user’s information (first name, last name, fullname…)

Suppose that we want to display the full name of the currently logged-in user instead of email. Add a getter method in the UserDetails class as shown below:

public class ShopmeUserDetails implements UserDetails {
	private User user;

	// override methods from UserDetails...
	
	public ShopmeUserDetails(User user) {
		this.user = user;
	}

	public String getFullName() {
		return this.user.getFullName();
	}
	
}

Then in the view, you can display full name of the user as follows:

<span sec:authentication="principal.fullName">Fullname</span>

Here, the principal object is actually a UserDetails object returned by the loadUserByUsername() method - So we can access any properties in this object. For example, if we have first name:

<span sec:authentication="principal.firstname">Firstname</span>

Note that to use sec:authentication attribute, you must declare this dependency:

<dependency>
    <groupId>org.thymeleaf.extras</groupId>
    <artifactId>thymeleaf-extras-springsecurity5</artifactId>
</dependency>

And declare an XML namespace:

<html xmlns:th="http://www.thymeleaf.org"
	xmlns:sec="https://www.thymeleaf.org/thymeleaf-extras-springsecurity5">

  

3. Display user’s assigned roles

To show the assigned roles (authorities) of the currently logged-in user, write the following line of code:

<span sec:authentication="principal.authorities">Roles</span>

It will call the getAuthorities() method of the UserDetails class.

 

4. Get UserDetails object in Spring Controller

Certainly there will be a case in which we want to get the UserDetails object that represent the currently logged-in user in Java code, e.g. a handler method a Spring controller class. The simplest way is using the @AuthenticationPrincipal annotation as shown in the example below:

package net.codejava;

import org.springframework.security.core.annotation.AuthenticationPrincipal;

@Controller
public class AccountController {

	@Autowired
	private UserServices service;
	
	@GetMapping("/account")
	public String viewUserAccountForm(
			@AuthenticationPrincipal ShopmeUserDetails userDetails,
			Model model) {
		String userEmail = userDetails.getUsername();
		User user = service.getByEmail(userEmail);
		
		model.addAttribute("user", user);
		model.addAttribute("pageTitle", "Account Details");
		
		return "users/account_form";
	}
}

As you can see, we can declare the type of the UserDetails object right after the @AuthenticationPrincipal annotation – very simple and convenient, right?

If you want to see the coding in action, I recommend you to watch the video below:

 

My Spring Security Tutorials:

 

Other Spring Boot Tutorials:


About the Author:

is certified Java programmer (SCJP and SCWCD). He began programming with Java back in the days of Java 1.4 and has been passionate about it ever since. You can connect with him on Facebook and watch his Java videos on YouTube.



Add comment