Spring Security - Retrieving User Information



Spring Security provides user information in SecurityContext once user is authenticated. We can retrieve user details in couple of ways. Let's discuss them one by one.

Using SecurityContextHolder

SecurityContextHolder provides static access to the security context and can be used to get the Authentication instance. Once Authentication instance is available, we can get the username easily as shown below:

Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
String username = authentication.getName();

This approch is useful for any class to retrieve the user details and is not limited to controller classes.

Using Principal

We can use Principal as an argument to a controller class method which then can be used to get the name of the user as shown below:

@Controller 
public class AuthController { 
...
@GetMapping("/admin")
public String admin(Principal principal) {
   String username = principal.getName();
   System.out.println("AuthController.admin()::Username: " + username);
   ...
}

Using Authetication

We can use Authentication as an argument to a controller class method which then can be used to get the name of the user and role as shown below:

@Controller 
public class AuthController { 
...
@GetMapping("/admin")
public String admin(Authentication authentication) {
   String username = authentication.getName();
   System.out.println("AuthController.admin()::Username: " + username);
   
   UserDetails userDetails = (UserDetails) authentication.getPrincipal();
   System.out.println("User Role: " + userDetails.getAuthorities());
   ...
}

Using HttpServletRequest

We can use HttpServletRequest as an argument to a controller class method to get the UserPrincipal which then can be used to get the name of the user as shown below:

@Controller 
public class AuthController { 
...
@GetMapping("/admin")
public String admin(HttpServletRequest request) {
   Principal principal = request.getUserPrincipal();
   String username = principal.getName();
   System.out.println("AuthController.admin()::Username: " + username);
   ...
}

Using @AuthenticationPrincipal to inject UserDetails

We can use @AuthenticationPrincipal annotation in a controller class method to get the UserDetails which then can be used to get the name of the user as shown below:

@Controller 
public class AuthController { 
...
@GetMapping("/admin")
public String admin(@AuthenticationPrincipal UserDetails userDetails) {
   String username = userDetails.getUsername();
   System.out.println("AuthController.admin()::Username: " + username);
   ...
}

Using Thymeleaf templating engine

Thymeleaf is a server side web templating engine and provides an easy integration with Spring MVC. We can specify authentication tag to get the username as shown below:

<!DOCTYPE html> 
<html xmlns="http://www.w3.org/1999/xhtml" 
   xmlns:th="https://www.thymeleaf.org" 
   xmlns:sec="https://www.thymeleaf.org/thymeleaf-extras-springsecurity6"> 
   ...
      <h1 th:inline="text">Hello <span sec:authentication="name"></span>!</h1> 
   ...
<html> 

We need to add following thymeleaf spring dependencies to integrate thymeleaf with Spring security.

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
   <groupId>org.thymeleaf.extras</groupId>
   <artifactId>thymeleaf-extras-springsecurity6</artifactId>
</dependency>

Now let's see various options with following complete code in action.

Before you start writing your first example using Spring framework, you have to make sure that you have set up your Spring environment properly as explained in Spring Security - Environment Setup Chapter. We also assume that you have a bit of working knowledge on Spring Tool Suite IDE.

Now let us proceed to write a Spring MVC based Application managed by Maven, which will ask user to login, authenticate user and then provide option to logout using Spring Security Form Login Feature.

Create Project using Spring Initializr

Spring Initializr is great way to start with Spring Boot project. It provides a easy to use User Interface to create a project, add dependencies, select java runtime etc. It generates a skeleton project structure which once downloaded can be imported in spring tool suite and we can proceed with our readymade project structure.

We're choosing a maven project, naming the project as formlogin, with java version as 21. Following dependencies are added:

  • Spring Web

  • Spring Security

  • Thymeleaf

  • Spring Boot DevTools

Spring Initializr

Thymeleaf is a templating engine for Java. It allows us to quickly develop static or dynamic web pages for rendering in the browser. It is extremely extensible and allows us to define and customize the processing of our templates in fine detail. In addition to this, we can learn more about Thymeleaf by clicking this link.

Let's move on to generate our project and download it. We then extract it to a folder of our choice and use any IDE to open it. I shall be using Spring Tools Suite 4. It is available for free downloading from the https://spring.io/tools website and is optimized for spring applications.

pom.xml with all relevant dependencies

Let's take a look at our pom.xml file. It should look something similar to this −

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-parent</artifactId>
      <version>3.3.1</version>
      <relativePath/> <!-- lookup parent from repository -->
   </parent>
   <groupId>com.tutorialspoint.security</groupId>
   <artifactId>formlogin</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <name>formlogin</name>
   <description>Demo project for Spring Boot</description>
   <url/>
   <licenses>
      <license/>
   </licenses>
   <developers>
      <developer/>
   </developers>
   <scm>
      <connection/>
      <developerConnection/>
      <tag/>
      <url/>
   </scm>
   <properties>
      <java.version>21</java.version>
   </properties>
   <dependencies>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-security</artifactId>
      </dependency>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-thymeleaf</artifactId>
      </dependency>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-web</artifactId>
      </dependency>
      <dependency>
         <groupId>org.thymeleaf.extras</groupId>
         <artifactId>thymeleaf-extras-springsecurity6</artifactId>
      </dependency>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-devtools</artifactId>
         <scope>runtime</scope>
         <optional>true</optional>
      </dependency>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-test</artifactId>
         <scope>test</scope>
      </dependency>
      <dependency>
         <groupId>org.springframework.security</groupId>
         <artifactId>spring-security-test</artifactId>
         <scope>test</scope>
      </dependency>
   </dependencies>
   <build>
      <plugins>
         <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
         </plugin>
      </plugins>
   </build>
</project>

Spring Security Configuration Class

Inside of our config package, we have created the WebSecurityConfig class. We shall be using this class for our security configurations, so let's annotate it with an @Configuration annotation and @EnableWebSecurity. As a result, Spring Security knows to treat this class a configuration class. As we can see, configuring applications have been made very easy by Spring.

WebSecurityConfig

package com.tutorialspoint.security.formlogin.config; 

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain; 

@Configuration 
@EnableWebSecurity
public class WebSecurityConfig  { 

   @Bean 
   protected UserDetailsService userDetailsService() {
      UserDetails user = User.builder()
         .username("user")
         .password(passwordEncoder().encode("user123"))
         .roles("USER")
         .build();
      UserDetails admin = User.builder()
         .username("admin")
         .password(passwordEncoder().encode("admin123"))
         .roles("USER", "ADMIN")
         .build();
      return new InMemoryUserDetailsManager(user, admin);
   }

   @Bean 
   protected PasswordEncoder passwordEncoder() { 
      return new BCryptPasswordEncoder(); 
   }

   @Bean
   protected SecurityFilterChain filterChain(HttpSecurity http) throws Exception { 
      return http
         .csrf(AbstractHttpConfigurer::disable)
         .authorizeHttpRequests(
            request -> request.requestMatchers("/login").permitAll()
         .requestMatchers("/**").authenticated()
      )
      .formLogin(form -> form.loginPage("/login")
      .defaultSuccessUrl("/")
      .failureUrl("/login?error=true")
      .permitAll())          
      .logout(config -> config  
      .logoutUrl("/logout") 
      .logoutSuccessUrl("/login")) 
      .build();
   }   
}

Controller Class

In this class, we've created a mapping for multiple endpoints for the index, login, admin pages of this application.

AuthController

package com.tutorialspoint.security.formlogin.controllers; 

import java.security.Principal;

import org.springframework.security.core.Authentication;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Controller; 
import org.springframework.web.bind.annotation.GetMapping;

import jakarta.servlet.http.HttpServletRequest; 

@Controller 
public class AuthController { 
   @GetMapping("/") 
   public String home(Authentication authentication, HttpServletRequest request) { 
      // get username from Authetication instance
      String username = authentication.getName();
      System.out.println("AuthController.home()::Username: " + username);

      // get principal instance from Authentication instance to get user role
      UserDetails userDetails = (UserDetails) authentication.getPrincipal();
      System.out.println("User Role: " + userDetails.getAuthorities());

      // get principal instance from HTTP Request
      Principal principal = request.getUserPrincipal();
      // get username
      username = principal.getName();

      System.out.println("AuthController.home()::principal.getName(): " + username);
      return "index"; 
   }

   @GetMapping("/login") 
   public String login() { 
      return "login"; 
   }
   @GetMapping("/user")
   public String user() {
      // get authentication instance from Security Context
      Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
      // get the user name
      String username = authentication.getName();
      System.out.println("AuthController.user()::Username: " + username);
      return "user";
   }
   @GetMapping("/admin")
   public String admin(Principal principal, @AuthenticationPrincipal UserDetails userDetails) {
      // get the username from principal instance
      String username = principal.getName();
      System.out.println("AuthController.admin()::Username: " + username);

      // get the username from userdetails instance
      username = userDetails.getUsername();
      System.out.println("AuthController.admin()::userDetails.getUsername(): " + username);
      return "admin";
   }
}

Views

Create index.html in /src/main/resources/templates folder with following content to act as a home page.

index.html

<!DOCTYPE html> 
<html xmlns="http://www.w3.org/1999/xhtml" 
   xmlns:th="https://www.thymeleaf.org" 
   xmlns:sec="https://www.thymeleaf.org/thymeleaf-extras-springsecurity6"> 
   <head> 
      <title>
         Hello World!
      </title> 
   </head>
   <body> 
      <h1 th:inline="text">Hello World!</h1> 
      <a href="/logout" alt="logout">Sign Out</a>
   </body> 
<html> 

Create user.html in /src/main/resources/templates folder with following content to act as user page.

user.html

<!DOCTYPE html> 
<html xmlns="http://www.w3.org/1999/xhtml" 
   xmlns:th="https://www.thymeleaf.org" 
   xmlns:sec="https://www.thymeleaf.org/thymeleaf-extras-springsecurity6"> 
   <head> 
      <title>
         Hello User!
      </title> 
   </head>
   <body> 
      <p>User Dashboard</p>
      <h1 th:inline="text">Hello <span sec:authentication="name"></span>!</h1> 
      <a href="/logout" alt="logout">Sign Out</a>
   </body> 
<html> 

Create admin.html in /src/main/resources/templates folder with following content to act as admin page.

admin.html

<!DOCTYPE html> 
<html xmlns="http://www.w3.org/1999/xhtml" 
   xmlns:th="https://www.thymeleaf.org" 
   xmlns:sec="https://www.thymeleaf.org/thymeleaf-extras-springsecurity6"> 
   <head> 
      <title>
         Hello User!
      </title> 
   </head>
   <body> 
      <p>User Dashboard</p>
      <h1 th:inline="text">Hello <span sec:authentication="name"></span>!</h1> 
      <a href="/logout" alt="logout">Sign Out</a>
   </body> 
<html> 

Running the Application

As we've all component ready, let's run the Application. Right Click on the project, select Run As and then Spring Boot App.

It will boot up the application and once application is started, we can run localhost:8080 to check the changes.

Output

Now open localhost:8080, you can see the login page.

Form Authentication

Home Page

Form Authentication with Valid Credential

Check the logs for Home Page

Now check the application logs. It will have following entries apart from Spring boot logs:

AuthController.home()::Username: user
User Role: [ROLE_USER]
AuthController.home()::principal.getName(): user

User Page

Now open localhost:8080/user, you can check the following logs in application logs.

AuthController.user()::Username: user

You can check the username being shown in html as well.

Form Authentication

Admin Page

Now open localhost:8080/admin, you can check the following logs in application logs.

AuthController.admin()::Username: user
AuthController.admin()::userDetails.getUsername(): user
Advertisements