Basics Of Spring Security User Management

User management in an application defines how a user is created/updated, the characteristics of a user(credentials, email address, a flag to indicate account status), and the authentication process. Also, if we are using spring security in our application, It is important to understand the basics of spring security user management.

In this article, we will learn how spring security handles user management. We will also learn the main components of Spring security user management.

We will also create a small example application and customize a few of the components of the user management.

Table of Contents

Components of user management

The below image shows the main components of Spring security user management.

Spring security user management

The main components and their role are:

  • UserDetailsManager: This interface extends UserDetailsService interface. It is also responsible for user create, updates, or delete operations.
  • UserDetailsService: This interface defines a method that finds the user by username.
  • UserDetails: This interface describes the user.
  • GrantedAuthority: GrantedAuthority interface represents the authorities that a user can have.

Customizing the user details

In this example, we will learn how to customize the default user representation provided by the spring security.

We will also create a Spring boot application with spring security dependency. We define a custom User class to represent the user and also create a custom user details service to load the user from an in-memory list.

Create an application

Create a Spring boot application with the following dependencies.

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

We have added the spring web starter dependency, and also the security starter dependencies to our applications pom.xml file.

Define a User details class

Create a custom java class with the name User that represents our application’s user.

Also, our custom user class needs to implement Spring security’s UserDetails interface.

Finally, the below code shows a simple implementation of the UserDetails contract.

public class User implements UserDetails {
    private static final long serialVersionUID = 1L;
    private final String username;
    private final String password;
    private final String authority;
    public User(String username, String password, String authority) {
        this.username = username;
        this.password = password;
        this.authority = authority;
    }
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return List.of(() -> authority);
    }
    @Override
    public String getPassword() {
        return this.password;
    }
    @Override
    public String getUsername() {
        return this.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;
    }
}

The Spring securities UserDetails interface has the following methods:

  • getAuthorities(): This method returns all the authorities a user has. The GrantedAuthority contract represents user authority.
  • These authorities describe the privileges a user has(like read, write, update, etc.) or actions a user can perform. In our example, we also have a simple String field called authority that represents the user’s authority.
  • In our example, we have returned true for the below methods, as it is a simple implementation. We can also add the required logic to customize the behavior.
  • getPassword() & getUsername(): Returns the user credentials(password & username).
  • isAccountNonExpired(): Return true if user account is not expired.
  • isAccountNonLocked(): Return true if user account is not locked.
  • isCredentialsNonExpired(): Return true if user credentials are not expired.
  • isEnabled(): Return true if user is enabled.

Implement a custom UserDetailsService

To use the newly created custom user details class, we need to implement the UserDetailsService interface.

The UserDetailsService is responsible for loading the user by username from a database/LDAP or any other storage(From a local collection in our example).

Create a custom InMemoryUserDetailsService class that implements UserDetailsService interface.

public class InMemoryUserDetailsService implements UserDetailsService {

    private final List<UserDetails> users;

    public InMemoryUserDetailsService(List<UserDetails> users) {
        this.users = users;
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        return users.stream()
                .filter(u -> u.getUsername().equals(username))
                .findFirst()
                .orElseThrow(() -> new UsernameNotFoundException("Username not found!!"));
    }
}

We are maintaining users in a local collection called users.

The loadUserByUsername method searches for available user instances from the “users” collection and returns the user instance if the username matches.

If the username doesn’t match any of the existing users, it throws UsernameNotFoundException.

Define the security configuration

To wire the custom UserDetails and UserDetailsService implementation to spring security, we need to configure the UserDetailsService bean.

Also, create a spring configuration java class with the name AuthConfig, as shown below.

@Configuration
public class AuthConfig {
    
    @Bean
    public UserDetailsService userDetailsService() {
        UserDetails u = new User("arun", "12345", "READ");
        List<UserDetails> users = List.of(u);
        return new InMemoryUserDetailsService(users);
    }
    @Bean
    public PasswordEncoder passwordEncoder() {
        return NoOpPasswordEncoder.getInstance();
    }
}

We have created an instance of the User class, which is our customized UserDetails instance.

The user will have a username arun, password 12345, and an authority READ.

We have also created a list of users and passing it to the class InMemoryUserDetailsService‘s constructor that implementations the UserDetailsSerice interface.

The collection of users passed to the constructor adds the users into the locally defined in-memory users list of the InMemoryUserDetailsService class.

We also have to define a Password encoder bean if we are customizing the UserDetailsService.


Create a simple HTTP GET endpoint, as shown below.

The user will land on this path after successful authentication.

@RestController
public class HelloRestController {
    
    @GetMapping("/")
    public String getMessage() {
        return "Hello!!";
    }
}

Testing the implementation

Start the Spring boot application. Also, access the application from a browser(at location http://localhost:8080).

Spring security displays the default login page, as shown below.

Enter the credentials of the user and click on the Sign-in button.

custom user details example spring boot

Finally, we get a hello message if the user gets authenticated successfully.

custom user details example spring security

Conclusion

In this article, we learned how spring security represents the user details, user authorities, etc.

We also learned how spring security provides basic functionalities required to load, manage users, and their authentication.

We have also customized user details by creating a simple user implementation and custom user details service to use the custom user implementation.

Example code is available on GitHub.

Basics Of Spring Security User Management
Scroll to top

Discover more from ASB Notebook

Subscribe now to keep reading and get access to the full archive.

Continue reading