Java Spring Extend Userdetails Example
Posted on January 6, 2018
The UserDetailsService is a core interface in Spring Security framework, which is used to retrieve the user's authentication and authorization information.
It has a single read-only method named as loadUserByUsername() which locate the user based on the username.
This post shows you how to create a custom UserDetailsService for authentication in Spring MVC web application.
Tools and technologies used for this application are -
- Spring Security 5.0.0.RELEASE
- Spring MVC 5.0.2.RELEASE
- Servlet API 3.1.0
- Java SE 9
- Maven 3.5.2
- Eclipse Oxygen.2 Release (4.7.2)
- Jetty Maven plugin 9.4.8
Project structure
Final project structure of our application will look like as follows.
Related - How to create a web project using maven build tool in eclipse IDE.
Jar dependencies
Openpom.xml file of your maven project and add the following dependencies in it.
pom.xml
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.boraji.tutorial.springsecurity</groupId> <artifactId>spring-security-user-details-service-example</artifactId> <version>0.0.1-SNAPSHOT</version> <name>Spring Security - Custom UserDetailsService example</name> <packaging>war</packaging> <properties> <maven.compiler.source>9</maven.compiler.source> <maven.compiler.target>9</maven.compiler.target> <failOnMissingWebXml>false</failOnMissingWebXml> </properties> <dependencies> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-web</artifactId> <version>5.0.0.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> <version>5.0.0.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.0.2.RELEASE</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>javax.servlet.jsp-api</artifactId> <version>2.3.1</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet.jsp.jstl</groupId> <artifactId>javax.servlet.jsp.jstl-api</artifactId> <version>1.2.1</version> </dependency> <dependency> <groupId>taglibs</groupId> <artifactId>standard</artifactId> <version>1.1.2</version> </dependency> </dependencies> <build> <plugins> <!-- Maven jetty plugin for testing war --> <plugin> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-maven-plugin</artifactId> <version>9.4.8.v20171121</version> </plugin> </plugins> </build> </project> Creating Custom UserDetailsService
To create a custom user service, you need to implement the UserDetailsService interface and override the loadUserByUsername() method.
CreateUserDetailsServiceImp class undercom.boraji.tutorial.spring.service package as follows.
UserDetailsServiceImp.java
package com.boraji.tutorial.spring.service; import org.springframework.security.core.userdetails.User.UserBuilder; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import com.boraji.tutorial.spring.model.User; public class UserDetailsServiceImp implements UserDetailsService { @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { /*Here we are using dummy data, you need to load user data from database or other third party application*/ User user = findUserbyUername(username); UserBuilder builder = null; if (user != null) { builder = org.springframework.security.core.userdetails.User.withUsername(username); builder.password(new BCryptPasswordEncoder().encode(user.getPassword())); builder.roles(user.getRoles()); } else { throw new UsernameNotFoundException("User not found."); } return builder.build(); } private User findUserbyUername(String username) { if(username.equalsIgnoreCase("admin")) { return new User(username, "admin123", "ADMIN"); } return null; } } Next, create User model class undercom.boraji.tutorial.spring.model package as follows.
User.java
package com.boraji.tutorial.spring.model; public class User { private String username; private String password; private String[] roles; public User(String username, String password, String... roles) { this.username = username; this.password = password; this.roles = roles; } // Getter and Setter methods } Note :- You can useUser model class to map the user data to a database table etc.
Spring Security configuration
To configure Spring Security in Spring MVC application you need to -
- Create a
springSecurityFilterChainServlet Filter for protecting and validating all URLs by create a@Configurationclass. - Register the
springSecurityFilterChainfilter with war.
Now, create a@Configuration class by extending theWebSecurityConfigurerAdapter class and annotate it with @EnableWebSecurity.
Define your custom UserDetailsService class as a @Bean in web security @Configuration class as follows.
WebSecurityConfig.java
package com.boraji.tutorial.spring.config; import org.springframework.context.annotation.Bean; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; 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.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import com.boraji.tutorial.spring.service.UserDetailsServiceImp; @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Bean public UserDetailsService userDetailsService() { return new UserDetailsServiceImp(); }; @Bean public BCryptPasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); }; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService()).passwordEncoder(passwordEncoder()); } @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests().anyRequest().hasAnyRole("ADMIN", "USER") .and() .formLogin() .and() .logout().permitAll().logoutSuccessUrl("/login") .and() .csrf().disable(); } } Next, createSecurityWebApplicationInitializer class by extending theAbstractSecurityWebApplicationInitializer to register thespringSecurityFilterChain filter.
SecurityWebApplicationInitializer.java
package com.boraji.tutorial.spring.config; import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer; public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer { } Spring MVC configuration
To enable the Spring MVC in your application, you need to annotate your@Configuration class with@EnableWebMvc annotation.
In this example, we are using the JSP views. So create a @Configuration class and override the configureViewResolvers() method to register the JSP view resolver.
Also, you can override the addViewControllers() method to map and render the default login page generated by Spring Security.
WebConfig.java
package com.boraji.tutorial.spring.config; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; import org.springframework.web.servlet.config.annotation.ViewResolverRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration @EnableWebMvc @ComponentScan(basePackages = { "com.boraji.tutorial.spring.controller" }) public class WebConfig implements WebMvcConfigurer { @Override public void configureViewResolvers(ViewResolverRegistry registry) { registry.jsp().prefix("/WEB-INF/views/").suffix(".jsp"); } @Override public void addViewControllers(ViewControllerRegistry registry) { registry.addViewController("/login").setViewName("login"); } } Servlet container Initialization and configuration
In Spring MVC, TheDispatcherServlet needs to be declared and mapped for processing all requests either using java orweb.xmlconfiguration.
In a Servlet 3.0+ environment, you can useAbstractAnnotationConfigDispatcherServletInitializer class to register and initialize theDispatcherServlet programmatically as follows.
MvcWebApplicationInitializer.java
package com.boraji.tutorial.spring.config; import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; public class MvcWebApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { // Load spring security configuration @Override protected Class<?>[] getRootConfigClasses() { return new Class[] { WebSecurityConfig.class }; } // Load spring web configuration @Override protected Class<?>[] getServletConfigClasses() { return new Class[] { WebConfig.class }; } @Override protected String[] getServletMappings() { return new String[] { "/" }; } } Controller class
Create a simple@Controller class undercom.boraji.tutorial.spring.controller package as follows.
MyContoller.java
package com.boraji.tutorial.spring.controller; import java.security.Principal; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; @Controller public class MyContoller { @GetMapping("/") public String index(Model model, Principal principal) { model.addAttribute("message", "You are logged in as " + principal.getName()); return "index"; } } JSP views
Create anindex.jsp file undersrc\main\webapp\WEB-INF\views folder and write the following code in it.
index.jsp
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <title>Spring Security 5</title> </head> <body> <h1>Spring Security - Custom UserDetailsService Example</h1> <h2>${message}</h2> <form action="/logout" method="post"> <input value="Logout" type="submit"> </form> </body> </html> Run application
Use the following maven command to run your application.
mvn jetty:run (This command deploy the webapp from its sources, instead of build war).
Enter the http://localhost:8080/ URL in browser's address bar to test our application.
On entering the URL, you will see the login page asking for username and password as follows.
On successful login, you will see the index page as follows.
Source: https://www.boraji.com/spring-security-5-custom-userdetailsservice-example
0 Response to "Java Spring Extend Userdetails Example"
Post a Comment