”;
In Spring MVC applications using JSP, we can use the Spring Security tags for applying security constraints as well as for accessing security information. Spring Security Tag library provides basic support for such operations. Using such tags, we can control the information displayed to the user based on his roles or permissions. Also, we can include CSRF protection features in our forms.
To use Spring security tags, we must have the security taglib declared in our JSP file.
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>
Now, we can use Spring Security tags with the sec prefix. Let”s now see the usage of the tags.
The authorize Tag
The first tag we will be discussing is the authorize tag. Let’s check out some usage examples.
<sec:authorize access="!isAuthenticated()"> Login </sec:authorize> <sec:authorize access="isAuthenticated()"> Logout </sec:authorize> <sec:authorize access="hasRole(''ADMIN'')"> Hello Admin. </sec:authorize>
As we can see, we can use this tag to hide or show sections of information based on access or roles.
-
hasRole(ADMIN) − evaluates to true if the current user has the admin role.
-
hasAnyRole(‘ADMIN’,’USER’) − evaluates to true if the current user has any of the listed roles
-
isAnonymous() − evaluates to true if the current user is an anonymous user
-
isRememberMe() − evaluates to true if the current user is a remember-me user
-
isFullyAuthenticated() − evaluates to true if the user is authenticated and is neither anonymous nor a remember-me user
As we can see, the access attribute is where the web-security expression is specified. Then, Spring Security evaluates the expression. The evaluation is generally delegated to SecurityExpressionHandler<FilterInvocation>, which is defined in the application context. If it returns true, then the user can get access to the information given in that section.
If we use the authorize tag with Spring Security ‘s Permission Evaluator, we can also check user permissions as given below −
<p sec:authorize="hasPermission(#domain,''read'') or hasPermission(#domain,''write'')"> This content is visible to users who have read or write permission. </p>
We can also allow or restrict the user from clicking on certain links within our content.
<a sec:authorize href="/admin"> This content will only be visible to users who are authorized to send requests to the "/admin" URL. </agt;
The authentication tag
When we want access to the current Authentication object stored in the Spring Security Context, we can use the authentication tag. Then we can use it to render properties of the object directly in our JSP page. For example, if we want to render the principal property of the Authentication object in our page, we can do it as follows −
<p sec:authentication="name" />
The csrfInput Tag
We can use the csrfInput tag to insert a hidden form field with the correct values for the CSRF protection token when CSRF protection is enabled. If CSRF protection is not enabled, this tag outputs nothing.
We can place the tag within the HTML <form></form> block along with other input fields. However, we must not place the tag within the <form:form></form:form> block as Spring Security automatically inserts a CSRF form field within those tags and also takes care of Spring forms automatically.
<form method="post" action="/do/something"> <sec:csrfInput /> Username:<br /> <input type="text" username="username" /> ... </form>
The csrfMetaTags Tag
We can use this tag to insert meta tags which contain the CSRF protection token form field and header names and CSRF protection token value. These meta tags can be useful for employing CSRF protection within Javascript in our application. However, this tag only works when we have enabled CSRF protection in our application, otherwise, this tag outputs nothing.
<html> <head> <title>CSRF Protection in Javascript</title> <sec:csrfMetaTags /> <script type="text/javascript" language="javascript"> var csrfParam = $("meta[name=''_csrf_param'']").attr("content"); var csrfToken = $("meta[name=''_csrf'']").attr("content"); </script> </head> <body> ... </body> </html>
Let us start actual programming with Spring Security. Before you start writing your 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
-
Spring Boot DevTools
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 “/” endpoint, “/login” and “/admin” for the index page, login page and admin page of this application respectively.
AuthController.java
package com.tutorialspoint.security.formlogin.controllers; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; @Controller public class AuthController { @GetMapping("/") public String home() { return "index"; } @GetMapping("/login") public String login() { return "login"; } @GetMapping("/admin") public String admin() { 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-springsecurity3"> <head> <title> Hello World! </title> </head> <body> <h1 th:inline="text">Hello World!</h1> <form th:action="@{/logout}" method="post"> <input type="submit" value="Sign Out"/> </form> </body> <html>
Let”s create the login.html in /src/main/resources/templates folder with following content to act as a login page. We”re using default name username, password and remember-me for text fields. In case of other name, we need to set the same in spring security config class as well.
login.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-springsecurity3"> <head> <title>Spring Security Example</title> </head> <body> <div th:if="${param.error}"> <p>Bad Credentials</p> </div> <div th:if="${param.logout}">You have been logged out.</div> <form th:action="@{/login}" method="post"> <h1>Please sign in</h1> <table> <tr> <td><label for="username"><b>Username</b></label></td> <td><input type="text" placeholder="Enter Username" name="username" id="username" required></td> </tr> <tr> <td><label for="password"><b>Password</b></label></td> <td><input type="password" placeholder="Enter Password" name="password" id="password" required></td> </tr> <tr> <td><label for="remember-me"><b>Remember Me</b></label> </td> <td><input type="checkbox" name="remember-me" /></td> </tr> <tr> <td> </td> <td><input type="submit" value="Sign In" /></td> </tr> </table> </form> </body> </html>
Let”s create admin.html to use authorize tag. Here, we have added <%@ taglib uri=”http://www.springframework.org/security/tags” prefix=”sec”%>. This is going to let us the Spring security tag libs as discussed before.
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 Admin! </title> </head> <body> <p>Admin Console</p> <h1 th:inline="text">Welcome <span sec:authentication="name"></span>!</h1> <p sec:authorize="hasRole(''ADMIN'')"> Control Panel </p> <a href="/logout" alt="logout">Sign Out</a> </body> <html>
As we can see, we have the added the authorize tag around the content. This content is will be only accessible by our admin. Any other user accessing this page will not be able to view this content. Another tag authentication is used to get the principal in order to retrieve the username of the user logged in.
Running the Application
Once 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 our login page.
Login Page with Admin Details entered
Admin Page
When we enter valid credential for a Admin and it will load home page. Now open localhost:8080/admin. You can see the Control Panel text visible for admin user.
Login Page with User Details entered
Now logout from the application by clicking the signout link and login using user credential.
Admin Page for User
When we enter valid credential for a User and it will load home page. Now load localhost:8080/admin to open admin page. You can see the Control Panel text is not visible for normal user.
”;