Security Spring MVC Framework in Spring Boot


On the Eclipse, create a Spring MVC project in Spring Boot

Enter Project Information:

  • Name: LearnSpringMVCWithRealApps
  • Group: com.demo
  • Artifact: LearnSpringMVCWithRealApps
  • Description: Learn Spring MVC with Real Apps
  • Package: com.demo

Select the technologies and libraries to be used:

  • Web
  • Security

Click Next button to show Site Information for project

Click Finish button to finish create Spring MVC project




<?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
						http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>com.demo</groupId>
	<artifactId>LearnSpringMVCWithRealApps</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>LearnSpringMVCWithRealApps</name>
	<description>Learn Spring MVC with Real Apps</description>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.0.5.RELEASE</version>
		<relativePath /> <!-- lookup parent from repository -->
	</parent>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<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>

		<!-- JSTL tag lib -->
		<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>

		<!-- Tomcat for JSP rendering -->
		<dependency>
			<groupId>org.apache.tomcat.embed</groupId>
			<artifactId>tomcat-embed-jasper</artifactId>
			<scope>provided</scope>
		</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.mvc.view.prefix = /WEB-INF/views/
spring.mvc.view.suffix = .jsp
spring.mvc.static-path-pattern=/resources/**

server.port=9596

Create new package named com.demo.entities. In this package, create new entity as below:

package com.demo.entities;

public class Account {

	private String username;
	private String password;
	private String[] roles;

	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;
	}

	public String[] getRoles() {
		return roles;
	}

	public void setRoles(String[] roles) {
		this.roles = roles;
	}

	public Account(String username, String password, String[] roles) {
		super();
		this.username = username;
		this.password = password;
		this.roles = roles;
	}

	public Account() {
		super();
	}

}




Create new package named com.demo.repositories. In this package, create new repositories as below:

Create new interface named AccountRepository.java as below:

package com.demo.repositories;

import java.util.List;
import com.demo.entities.Account;

public interface AccountRepository {

	public List<Account> findAll();

	public Account find(String username);

}

Create new class named AccountRepositoryImpl.java as below:

package com.demo.repositories;

import java.util.ArrayList;
import java.util.List;
import org.springframework.stereotype.Repository;
import com.demo.entities.Account;

@Repository("accountRepository")
public class AccountRepositoryImpl implements AccountRepository {

	@Override
	public List<Account> findAll() {
		List<Account> accounts = new ArrayList<Account>();
		accounts.add(new Account("acc1", "$2a$04$YnS.4Ak1DPOV2YDjzPSl.ugIVk4/gXGPAHtSd/8g3fj2vJOuV49AG", new String[] {"ROLE_SUPER_ADMIN", "ROLE_ADMIN", "ROLE_EMPLOYEE"})); // password = 123
		accounts.add(new Account("acc2", "$2a$04$YnS.4Ak1DPOV2YDjzPSl.ugIVk4/gXGPAHtSd/8g3fj2vJOuV49AG", new String[] {"ROLE_ADMIN", "ROLE_EMPLOYEE"})); // password = 123
		accounts.add(new Account("acc3", "$2a$04$YnS.4Ak1DPOV2YDjzPSl.ugIVk4/gXGPAHtSd/8g3fj2vJOuV49AG", new String[] {"ROLE_EMPLOYEE"})); // password = 123
		return accounts;
	}

	@Override
	public Account find(String username) {
		for(Account account : this.findAll()) {
			if(account.getUsername().equalsIgnoreCase(username)) {
				return account;
			}
		}
		return null;
	}

}

Create new package named com.demo.services. In this package, create new services as below:

Create new interface named AccountService.java as below:

package com.demo.services;

import org.springframework.security.core.userdetails.UserDetailsService;

public interface AccountService extends UserDetailsService {

}

Create new class named AccountServiceImpl.java as below:

package com.demo.services;

import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import com.demo.entities.Account;
import com.demo.repositories.AccountRepository;

@Service("accountService")
public class AccountServiceImpl implements AccountService {

	@Autowired
	private AccountRepository accountRepository;

	@Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
		Account account = accountRepository.find(username);
		if (account == null) {
			throw new UsernameNotFoundException("Username not found for " + username);
		}
		List<GrantedAuthority> grantedAuthorities = new ArrayList<GrantedAuthority>();
		for (String role : account.getRoles()) {
			grantedAuthorities.add(new SimpleGrantedAuthority(role));
		}
		return new User(account.getUsername(), account.getPassword(), grantedAuthorities);
	}

}




Create new package named com.demo.controllers. In this package, create new controllers as below:

Create new controller named HomeController.java as below:

package com.demo.controllers;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
@RequestMapping("home")
public class HomeController {

	@RequestMapping(method = RequestMethod.GET)
	public String index() {
		return "home/index";
	}

}

Create new controller named SuperAdminController.java as below:

package com.demo.controllers;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
@RequestMapping("/superadmin**")
public class SuperAdminController {

	@RequestMapping(method = RequestMethod.GET)
	public String index() {
		return "superadmin/index";
	}

}

Create new controller named AdminController.java as below:

package com.demo.controllers;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
@RequestMapping("/admin**")
public class AdminController {

	@RequestMapping(method = RequestMethod.GET)
	public String index() {
		return "admin/index";
	}

}

Create new controller named EmployeeController.java as below:

package com.demo.controllers;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
@RequestMapping("/employee**")
public class EmployeeController {

	@RequestMapping(method = RequestMethod.GET)
	public String index() {
		return "employee/index";
	}

}

Create new controller named DashBoardController.java as below:

package com.demo.controllers;

import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
@RequestMapping("/dashboard")
public class DashBoardController {

	@RequestMapping(method = RequestMethod.GET)
	public String index() {
		return "redirect:/dashboard/login";
	}

	@RequestMapping(value = "login", method = RequestMethod.GET)
	public String login(
		@RequestParam(value = "error", required = false) String error,
		@RequestParam(value = "logout", required = false) String logout,
		ModelMap modelMap) {
		if(error != null) {
			modelMap.put("msg", "Invalid username or password!");
		}
		if(logout != null) {
			modelMap.put("msg", "Logout successfully");
		}
		return "dashboard/login";
	}

	@RequestMapping(value = "welcome", method = RequestMethod.GET)
	public String welcome() {
		return "dashboard/welcome";
	}

	@RequestMapping(value = "accessDenied", method = RequestMethod.GET)
	public String accessDenied() {
		return "dashboard/accessDenied";
	}

}




Create new folders with path webapp\WEB-INF\views in src\main. In views folder, create new JSP Pages as below:

Create new folder named home. Create new jsp file named index.jsp as below:

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
	pageEncoding="ISO-8859-1"%>
<html>
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
		<title>Home Page</title>
	</head>
	<body>

		<h3>Home Page</h3>

	</body>
</html>

Create new folder named superadmin. Create new jsp file named index.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Super Admin Page</title>
</head>
<body>

	<h3>Super Admin Page</h3>
	Welcome ${pageContext.request.userPrincipal.name}
	<br>
	<a href="${pageContext.request.contextPath }/dashboard/logout">Logout</a>

</body>
</html>

Create new folder named admin. Create new jsp file named index.jsp as below:

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Admin Page</title>
</head>
<body>

	<h3>Admin Page</h3>
	Welcome ${pageContext.request.userPrincipal.name}
	<br>
	<a href="${pageContext.request.contextPath }/dashboard/logout">Logout</a>

</body>
</html>

Create new folder named employee. Create new jsp file named index.jsp as below:

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Employee Page</title>
</head>
<body>

	<h3>Employee Page</h3>
	Welcome ${pageContext.request.userPrincipal.name}
	<br>
	<a href="${pageContext.request.contextPath }/dashboard/logout">Logout</a>

</body>
</html>

Create new folder named dashboard. In this folder, create new views as below:

Create new jsp file named login.jsp as below:

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
	pageEncoding="ISO-8859-1"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Login Page</title>
</head>
<body>

	<h3>Login Page</h3>
	${msg }
	<form method="post"
		action="${pageContext.request.contextPath }/dashboard/process-login">
		<table cellpadding="2" cellspacing="2">
			<tr>
				<td>Username</td>
				<td><input type="text" name="username"></td>
			</tr>
			<tr>
				<td>Password</td>
				<td><input type="password" name="password"></td>
			</tr>
			<tr>
				<td>&nbsp;</td>
				<td><input type="submit" value="Login"></td>
			</tr>
		</table>
	</form>

</body>
</html>

Create new jsp file named welcome.jsp as below:

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Welcome Page</title>
</head>
<body>

	<h3>Welcome Page</h3>
	Welcome ${pageContext.request.userPrincipal.name}
	<br>
	<a href="${pageContext.request.contextPath }/dashboard/logout">Logout</a>

</body>
</html>

Create new jsp file named accessDenied.jsp as below:

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Access Denied Page</title>
</head>
<body>

	<h3>Access Denied Page</h3>
	<a href="${pageContext.request.contextPath}/dashboard/welcome">Back</a>

</body>
</html>




In com.demo package, create new java class named SecurityConfiguration.java use for Spring Security as below:

package com.demo;

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.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.crypto.bcrypt.BCryptPasswordEncoder;

import com.demo.services.AccountService;

@EnableWebSecurity
@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

	@Autowired
	private AccountService accountService;

	@Override
	protected void configure(HttpSecurity httpSecurity) throws Exception {

		httpSecurity.cors().and().csrf().disable();

		httpSecurity.authorizeRequests()
					.antMatchers("/superadmin**").access("hasRole('ROLE_SUPER_ADMIN')")
					.antMatchers("/admin**").access("hasRole('ROLE_SUPER_ADMIN') or hasRole('ROLE_ADMIN')")
					.antMatchers("/employee**").access("hasRole('ROLE_SUPER_ADMIN') or hasRole('ROLE_ADMIN') or hasRole('ROLE_EMPLOYEE')")
					.and()
					.formLogin().loginPage("/dashboard/login")
					.loginProcessingUrl("/dashboard/process-login")
					.defaultSuccessUrl("/dashboard/welcome")
					.failureUrl("/dashboard/login?error")
					.usernameParameter("username").passwordParameter("password")
					.and()
					.logout().logoutUrl("/dashboard/logout")
					.logoutSuccessUrl("/dashboard/login?logout")
					.and()
					.exceptionHandling().accessDeniedPage("/dashboard/accessDenied");

	}

	@Autowired
	public void configureGlobal(AuthenticationManagerBuilder builder)
			throws Exception {
		builder.userDetailsService(accountService);
	}

	@Bean
	public BCryptPasswordEncoder encoder() {
		return new BCryptPasswordEncoder();
	}

}




Select LearnSpringMVCWithRealAppsApplication.java file in com.demo package, right click and select Run As/Spring Boot App menu

Access index method in home controller with following url: http://localhost:9596/home

Output

Test access index action in superadmin controller without account with url: http://localhost:9596/superadmin

Output

Test access index action in admin controller without account with url: http://localhost:9596/admin

Output

Test access index action in employee controller without account with url: http://localhost:9596/employee

Output

Test login with invalid account: username is abc and password is 123

Output

Test login with valid account: username is acc2 and password is 123. This account have roles: ROLE_ADMIN and ROLE_EMPLOYEE

Output

Use acc2 has logged access index action in superadmin controller with url: http://localhost:9596/superadmin

Output

Use acc2 has logged access index action in admin controller with url: http://localhost:9596/admin

Output

Use acc2 has logged access index action in employee controller with url: http://localhost:9596/employee

Output

I recommend you refer to the books below to learn more about the knowledge in this article: