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
springSecurityFilterChain
Servlet Filter for protecting and validating all URLs by create a@Configuration
class. - Register the
springSecurityFilterChain
filter 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.xml
configuration.
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