In this
post, I am going to explain how to add form based authentication to the
application.
@Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) public class ApplicationSecurityConfiguration extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity httpSecurity) throws Exception { httpSecurity.csrf().disable().authorizeRequests().antMatchers("/", "/public/*", "/css/*", "/js/*", "/hello").permitAll() .anyRequest().authenticated().and().formLogin().loginPage("/login").permitAll().and().logout() .invalidateHttpSession(true).clearAuthentication(true) .logoutRequestMatcher(new AntPathRequestMatcher("/logout")).logoutSuccessUrl("/logoutSuccess") .permitAll(); } }
Above
snippet tells the api /login redirect to login page and once user successfully
logged out, he will be redirected to logoutSuccess api.
Below APIs
do not require any authentication.
a.
/public/*
b.
/css/*
c.
/js/*
d.
/hello
Step 2:
Define a controller
that take care of /login and /logoutSuccess apis.
@Controller public class HomeController { @GetMapping("/hello") public ModelAndView sayHello(Model model) { ModelAndView modelAndView = new ModelAndView("hello"); return modelAndView; } @GetMapping("/secure") public ModelAndView securePage(Model model) { ModelAndView modelAndView = new ModelAndView("secure"); return modelAndView; } @GetMapping("/login") public ModelAndView loginPage(Model model) { ModelAndView modelAndView = new ModelAndView("login"); return modelAndView; } @GetMapping("/logoutSuccess") public ModelAndView logoutPage(Model model) { ModelAndView modelAndView = new ModelAndView("logoutSuccess"); return modelAndView; } @GetMapping("/") public ModelAndView homePage(Model model) { ModelAndView modelAndView = new ModelAndView("homePage"); return modelAndView; } }
Define
login.jsp, secure.jsp, logoutSuccess.jsp files under
src/main/webapp/WEB-INF/views folder.
Total
project structure looks like below.
Find the
below working application.
package com.sample.app.model; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.Table; @Entity @Table(name = "user") public class User { @Id @Column(name = "user_id") @GeneratedValue private int id; @Column(name = "user_name", nullable = false, unique = true) private String userName; @Column(name = "user_password", nullable = false) private String password; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
UserAuthorizations.java
package com.sample.app.model; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.Table; @Entity @Table(name = "user_authorizations") public class UserAuthorizations { @Id @Column(name = "user_auth_group_id") @GeneratedValue private int id; @Column(name = "user_name") private String userName; @Column(name = "auth_group") private String authGroup; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getAuthGroup() { return authGroup; } public void setAuthGroup(String authGroup) { this.authGroup = authGroup; } }
UserPrincipal.java
package com.sample.app.model; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; public class UserPrincipal implements UserDetails { private static final long serialVersionUID = 1L; private User user; private List<UserAuthorizations> authGroups; public UserPrincipal(final User user, final List<UserAuthorizations> authGroups) { super(); this.user = user; this.authGroups = authGroups; } @Override public Collection<? extends GrantedAuthority> getAuthorities() { if(authGroups == null) return Collections.EMPTY_SET; Set<GrantedAuthority> grantedAuthorities = new HashSet<> (); for(UserAuthorizations authGroup: authGroups) { grantedAuthorities.add(new SimpleGrantedAuthority(authGroup.getAuthGroup())); } return grantedAuthorities; } @Override public String getPassword() { return user.getPassword(); } @Override public String getUsername() { return user.getUserName(); } @Override public boolean isAccountNonExpired() { return true; } @Override public boolean isAccountNonLocked() { return true; } @Override public boolean isCredentialsNonExpired() { return true; } @Override public boolean isEnabled() { return true; } }
UserAuthorizationRepository.java
package com.sample.app.repository; import java.util.List; import org.springframework.data.jpa.repository.JpaRepository; import com.sample.app.model.UserAuthorizations; public interface UserAuthorizationRepository extends JpaRepository<UserAuthorizations, Integer>{ List<UserAuthorizations> findByUserName(String userName); }
UserRepository.java
package com.sample.app.repository; import org.springframework.data.jpa.repository.JpaRepository; import com.sample.app.model.User; public interface UserRepository extends JpaRepository<User, Integer> { User findByUserName(String userName); }
UserDetailsServiceImpl.java
package com.sample.app.service; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service; import com.sample.app.model.UserAuthorizations; import com.sample.app.model.User; import com.sample.app.model.UserPrincipal; import com.sample.app.repository.UserAuthorizationRepository; import com.sample.app.repository.UserRepository; @Service public class UserDetailsServiceImpl implements UserDetailsService{ @Autowired private UserRepository userRepository; @Autowired private UserAuthorizationRepository authGroupRepository; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { User user = userRepository.findByUserName(username); if(user == null) { throw new UsernameNotFoundException("User not exist"); } List<UserAuthorizations> authGroups = authGroupRepository.findByUserName(user.getUserName()); return new UserPrincipal(user, authGroups); } }
EmployeeController.java
package com.sample.app.controller; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("employees/") public class EmployeeController { @RequestMapping(value = "registered/count", method = RequestMethod.GET) @PreAuthorize("hasRole('ADMIN')") public String countEmps() { return "Total Registered Employees : "+ 1024; } @RequestMapping(value = "greetMe", method = RequestMethod.GET) @PreAuthorize("hasRole('USER') or hasRole('ADMIN')") public String greetMe() { return "Very Good Day to you"; } }
HomeController.java
package com.sample.app.controller; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.servlet.ModelAndView; @Controller public class HomeController { @GetMapping("/hello") public ModelAndView sayHello(Model model) { ModelAndView modelAndView = new ModelAndView("hello"); return modelAndView; } @GetMapping("/secure") public ModelAndView securePage(Model model) { ModelAndView modelAndView = new ModelAndView("secure"); return modelAndView; } @GetMapping("/login") public ModelAndView loginPage(Model model) { ModelAndView modelAndView = new ModelAndView("login"); return modelAndView; } @GetMapping("/logoutSuccess") public ModelAndView logoutPage(Model model) { ModelAndView modelAndView = new ModelAndView("logoutSuccess"); return modelAndView; } @GetMapping("/") public ModelAndView homePage(Model model) { ModelAndView modelAndView = new ModelAndView("homePage"); return modelAndView; } }
ApplicationSecurityConfiguration.java
package com.sample.app.config; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.dao.DaoAuthenticationProvider; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; 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.authority.mapping.GrantedAuthoritiesMapper; import org.springframework.security.core.authority.mapping.SimpleAuthorityMapper; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import com.sample.app.service.UserDetailsServiceImpl; @Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) public class ApplicationSecurityConfiguration extends WebSecurityConfigurerAdapter { @Autowired private UserDetailsServiceImpl userDetailsService; @Autowired private PasswordEncoder passwordEncoder; @Bean public DaoAuthenticationProvider authenticationProvider() { DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider(); daoAuthenticationProvider.setUserDetailsService(userDetailsService); daoAuthenticationProvider.setPasswordEncoder(passwordEncoder); daoAuthenticationProvider.setAuthoritiesMapper(authoritiesMapper()); return daoAuthenticationProvider; } @Override protected void configure(HttpSecurity httpSecurity) throws Exception { httpSecurity.csrf().disable().authorizeRequests().antMatchers("/", "/public/*", "/css/*", "/js/*", "/hello").permitAll() .anyRequest().authenticated().and().formLogin().loginPage("/login").permitAll().and().logout() .invalidateHttpSession(true).clearAuthentication(true) .logoutRequestMatcher(new AntPathRequestMatcher("/logout")).logoutSuccessUrl("/logoutSuccess") .permitAll(); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.authenticationProvider(authenticationProvider()); } @Bean public GrantedAuthoritiesMapper authoritiesMapper() { SimpleAuthorityMapper authorityMapper = new SimpleAuthorityMapper(); authorityMapper.setConvertToUpperCase(true); authorityMapper.setDefaultAuthority("ROLE_USER"); return authorityMapper; } }
App.java
package com.sample.app; import com.sample.app.model.User; import com.sample.app.model.UserAuthorizations; import java.util.Arrays; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import com.sample.app.repository.UserAuthorizationRepository; import com.sample.app.repository.UserRepository; @SpringBootApplication public class App { public static void main(String[] args) { SpringApplication.run(App.class, args); } @Bean public CommandLineRunner demo(UserRepository userRepository, UserAuthorizationRepository userAuthorizationRepository) { return (args) -> { User user1 = new User(); user1.setUserName("krishna"); user1.setPassword(passwordEncoder().encode("password123")); User user2 = new User(); user2.setUserName("ram"); user2.setPassword(passwordEncoder().encode("ram123")); UserAuthorizations userAuthorization1 = new UserAuthorizations(); userAuthorization1.setUserName("krishna"); userAuthorization1.setAuthGroup("ROLE_ADMIN"); UserAuthorizations userAuthorization2 = new UserAuthorizations(); userAuthorization2.setUserName("ram"); userAuthorization2.setAuthGroup("ROLE_USER"); userRepository.saveAll(Arrays.asList(user1, user2)); userAuthorizationRepository.saveAll(Arrays.asList(userAuthorization1, userAuthorization2)); }; } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(16); } }
Create
application.properties under src/main/resources folder.
application.properties
logging.level.root=WARN logging.level.org.hibernate=ERROR ## H2 specific properties spring.h2.console.enabled=true spring.h2.console.path=/h2 spring.datasource.url=jdbc:h2:file:~/db/myOrg.db;DB_CLOSE_ON_EXIT=FALSE;DB_CLOSE_DELAY=-1; spring.datasource.username=krishna spring.datasource.password=password123 spring.datasource.driverClassName=org.h2.Driver ## JPA specific properties # Creates the schema, destroying previous data. spring.jpa.hibernate.ddl-auto=create spring.jpa.database-platform=org.hibernate.dialect.H2Dialect #spring.jpa.show-sql=true #spring.jpa.properties.hibernate.format_sql=true ## Database connection pooling properties # Number of ms to wait before throwing an exception if no connection is available. spring.datasource.max-wait=10000 # Maximum number of active connections that can be allocated from this pool at the same time. spring.datasource.tomcat.max-active=10 spring.datasource.tomcat.max-idle=5 spring.datasource.tomcat.min-idle=3 spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true spring.mvc.view.prefix = /WEB-INF/views/ spring.mvc.view.suffix = .jsp
Create jsp
files under src/main/webapp/WEB-INF/views folder.
hello.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> </head> <body> <h1> Hello World<br /> </h1> </body> </html>
homepage.jsp
<%@page contentType="text/html" pageEncoding="UTF-8"%> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>JSP Page</title> </head> <body> <h1>Home Page</h1> </body> </html>
login.jsp
<%@page contentType="text/html" pageEncoding="UTF-8"%> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>JSP Page</title> </head> <body> <h1>Login Page</h1> <center> <h2>Signup Details</h2> <form action="/login" method="post"> <br />Username:<input type="text" name="username"> <br />Password:<input type="password" name="password"> <br /> <input type="submit" value="Submit"> </form> </center> </body> </html>
logoutSuccess.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> </head> <body> <h1>Logout successful</h1> </body> </html>
secure.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> </head> <body> <h1>This is protected file</h1> </body> </html>
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>springSecurity</groupId> <artifactId>springSecurity</artifactId> <version>1</version> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.6.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> </dependency> <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-jasper</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> </dependency> </dependencies> </project>
Run
App.java.
Open the
url ‘http://localhost:8080/’ in browser, you can see home page.
Open the
url ‘http://localhost:8080/secure’, you will be redirected to login page.
Login with user name ‘krishna’ and password
‘password123’. Click on Submit button after entering credentials, you will be redirected to secure.jsp page.
You can
download complete working application from this link.
No comments:
Post a Comment