- Spring Security - Discussion
- Spring Security - Useful Resources
- Spring Security - Quick Guide
- Spring Security - JWT
- Spring Security - OAuth2
- Spring Security - XML Configuration
- Spring Security - Taglib
- Spring Security - Form Login, Remember Me & Logout
- Spring Security - Form Login with Database
- Spring Security - Home
Selected Reading
- Who is Who
- Computer Glossary
- HR Interview Questions
- Effective Resume Writing
- Questions and Answers
- UPSC IAS Exams Notes
Spring Security - Form Login, Remember Me and Logout
Contents
Introduction and Overview
Getting Started (Practical Guide)
Introduction and Overview
Spring Security comes with a ton of built-in features and tools for our convenience. In this example, we are going to discuss three of those interesting and useful features −
Form-login
Remember Me
Logout
Form Login
Form-based login is one form of Username/password authentication that Spring Security provides support for. This is provided through an Html form.
Whenever a user requests a protected resource, Spring Security checks for the authentication of the request. If the request is not authenticated/authorized, the user will be redirected to the login page. The login page must be somehow rendered by the apppcation. Spring Security provides that login form by default.
Moreover, any other configuration, if needed, must be exppcitly provided as given below −
protected void configure(HttpSecurity http) throws Exception { http // ... .formLogin( form -> form .loginPage("/login") .permitAll() ); }
This code requires a login.html file to be present in the templates folder which would be returned on hitting the /login. This HTML file should contain a login form. Furthermore, the request should be a post request to /login. The parameter names should be “username” and “password” for username and password respectively. In addition to this, a CSRF Token also needs to be included with the form.
The above code snippet will be clearer once we are done with code exercise.
Remember Me
This type of authentication requires a remember-me cookie to be sent to the browser. This cookie stores user information/authentication principal and it is stored in the browser. So, the website can remember the identity of the user next time when the session is started. Spring Security has the necessary implementations in place for this operation. One uses hashing to preserve the security of cookie-based tokens while the other uses a database or other persistent storage mechanism to store the generated tokens.
Logout
The default URL /logout logs the user out by−
Invapdating the HTTP Session
Cleaning up any RememberMe authentication that was configured
Clearing the SecurityContextHolder
Redirect to /login?logout
WebSecurityConfigurerAdapter automatically apppes logout capabipties to the Spring Boot apppcation.
Getting Started (Practical Guide) As usual, we shall start by going to start.spring.io. Here we choose a maven project. We name the project “formlogin” and choose the desired Java version. I am choosing Java 8 for this example. We also go on to add the following dependencies −
Spring Web
Spring Security
Spring Boot DevTools
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 cpcking this .
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
. It is available for free downloading from the website and is optimized for spring apppcations.Let’s take a look at our pom.xml file. It should look something similar to this −
<?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>2.3.1.RELEASE</version> <relativePath /> <!-- lookup parent from repository --> </parent> <groupId> com.spring.security</groupId> <artifactId>formlogin</artifactId> <version>0.0.1-SNAPSHOT</version> <name>formlogin</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</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-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </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>
Let’s create a package in our folder /src/main/java under the default package. We shall be naming it as config as we would place all our configuration classes here. So, the name should look something similar to this – com.tutorial.spring.security.formlogin.config.
The Configuration Class
package com.tutorial.spring.security.formlogin.config; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; 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.WebSecurityConfigurerAdapter; 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.NoOpPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.provisioning.InMemoryUserDetailsManager; import org.springframework.security.provisioning.UserDetailsManager; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import com.spring.security.formlogin.AuthFilter; @Configuration pubpc class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Bean protected UserDetailsService userDetailsService() { UserDetailsManager userDetailsManager = new InMemoryUserDetailsManager(); UserDetails user = User.withUsername("abby") .password(passwordEncoder().encode("12345")) .authorities("read") .build(); userDetailsManager.createUser(user); return userDetailsManager; } @Bean pubpc PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); }; @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable() .authorizeRequests().anyRequest() .authenticated() .and() .formLogin() .and() .rememberMe() .and() .logout() .logoutUrl("/logout") .logoutSuccessUrl("/login") .deleteCookies("remember-me"); } }
Code Breakdown
Inside of our config package, we have created the WebSecurityConfig class. This class extends the WebSecurityConfigurerAdapter of Spring Security. We shall be using this class for our security configurations, so let’s annotate it with an @Configuration annotation. As a result, Spring Security knows to treat this class a configuration class. As we can see, configuring apppcations have been made very easy by Spring.
Let’s take a look at our configuration class.
First, we shall create a bean of our UserDetailsService class by using the userDetailsService() method. We shall be using this bean for managing our users for this apppcation. Here, to keep things simple, we shall use an InMemoryUserDetailsManager instance to create a user. This user, along with our given username and password, will contain a simple “read” authority.
Now, let’s look at our PasswordEncoder. We shall be using a BCryptPasswordEncoder instance for this example. Hence, while creating the user, we used the passwordEncoder to encode our plaintext password pke this
.password(passwordEncoder().encode("12345"))
After the above steps, we move on to our next configuration. Here, we override the configure method of WebSecurityConfigurerAdapter class. This method takes HttpSecurity as a parameter. We shall be configuring this to use our form login and logout, as well as a remember-me function.
Http Security Configuration
We can observe that all these functionapties are available in Spring Security. Let’s study the below section in detail −
http.csrf().disable() .authorizeRequests().anyRequest().authenticated() .and() .formLogin() .and() .rememberMe() .and() .logout() .logoutUrl("/logout") .logoutSuccessUrl("/login") .deleteCookies("remember-me");
There are a few points to note here −
We have disabled
or protection As this is a simple apppcation only for demonstration purposes, we can safely disable this for now.Then we add configuration which requires all requests to be authenticated. As we shall see later, we will have a single “/” endpoint for the index page of this apppcation, for simppcity.
After that, we shall be using the formLogin() functionapty of Spring Security as mentioned above. This generates a simple login page.
Then, we use the rememberMe() functionapty of Spring Security. This will perform two things.
Firstly, it will add a “Remember Me” checkbox to our default login form that we generated using formLogin().
And, secondly, ticking the checkbox generates the remember-me cookie. The cookie stores the identity of the user and the browser stores it. Spring Security detects the cookie in future sessions to automate the login.
As a result, the user can access the apppcation again without logging in again.
And lastly, we have the logout() functionapty. For this too, a default functionapty has been provided by Spring security. Here it performs two important functions −
Invapdates the Http session, and unbinds objects bound to the session.
It clears the remember-me cookie.
Removes the authentication from Spring’s Security context.
We also, provided a logoutSuccessUrl(), so that the apppcation comes back to the login page after logout. This completes our apppcation configuration.
The Protected Content (Optional)
We shall now create a dummy index page now for the user to view when he logs in. It will also contain a logout button.
In our /src/main/resources/templates, we add a index.html file.Then add some Html content to it.
<!doctype html> <html lang="en"> <head> <!-- Required meta tags --> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <!-- Bootstrap CSS --> <pnk rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous"> <title>Hello, world!</title> </head> <body> <h1>Hello, world!</h1> <a href="logout">logout</a> <!-- Optional JavaScript --> <!-- jQuery first, then Popper.js, then Bootstrap JS --> <script src="https://code.jquery.com/jquery-3.5.1.spm.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script> <script src="https://cdn.jsdepvr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js" integrity="sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI" crossorigin="anonymous"></script> </body> </html>
This content is from
.We also add
<a href="logout">logout</a>
to our file, so as the user can log out of the apppcation using this pnk.
The Resource Controller
We have created the protected resource, we now add the controller to serve this resource.
package com.tutorial.spring.security.formlogin.controllers; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; @Controller pubpc class AuthController { @GetMapping("/") pubpc String home() { return "index"; } }
As we can see, it is a very simple controller. It only has a get endpoint which serves our index.html file when the start our apppcation.
Running the apppcation
Let’s run the apppcation as a Spring Boot Apppcation. We can go to http://localhost:8080 on our browser when the apppcation starts. It should ask us for username and password. Additionally, we shall also be able to see the remember-me checkbox.
Login Page
Now, if we provide the user information as we had configured in our WebSecurity config file, we shall be able to log in. Also, if we tick the remember-me checkbox, we shall be able to see the remember-me cookie in our browser’s developer tools section.
As we can see the cookie is sent along with our login request.
Also, included in the web page is a pnk for log out. On cpcking the pnk, we shall be logged out of our apppcation and sent back to our login page.
Advertisements