Создайте простое приложение для входа и закрепите его с помощью Java Servlet Filter

1- Почкму используется безопасность?

Безопасность (Security) является важной частью приложения с перемещением важных данных в  Internet.

Authentication (Аутентификация)

 Аутентификация является процесс в котором авторизация на получение доступа (access privileges) пользователя подтверждается перед тем как они заходят в защищенный регион вебсайта ( Website). Есть 2 главных способа аутентификации: базовая аутентификация и на основании формы (Form-based authentication).

Basic Authentication (Базовая аутентификация).

С базовой аутентификацией, пользователь может получить доступ ко всем страницам (page) совершенно нормально, для страниц требующих аутентификацию, отобразиться окно чтобы пользователь ввел его username/password. Информация  username/password упакуется и отправится вместе с запросом (request) к  Server.
Когда пользователь вводит ссылку на браузере и нажимает на Enter для запроса на страницу (page). Информация  "User Agent" создаетя и отправляется вместе с запросом. Обычно данная информация включает информацию браузера пользователя, информацию операционной системы. В случае базовой аутентификации (basic authentication) информация  username/password упакована внутри  "User Agent".
В данной статье я не упоминаю детально про базовую аутентификацию.

Form-based Authentication (Аутентификация на основе форм)

Почти все вебсайты используют аутентификацию на основе форм (Form-based Authentication). Вебсайт разрешает пользователю получить доступ любые обычные страницы не требуя пароль. Но если пользователь получает доступ в защищенную страницу, она перенаправит к странице логина.
В данной статье я детально говорю про способ использования Servlet Filter для безопасности приложения  Java Web.

2- Понятие про Role и Principal

В безопасности есть 2 важных понятия это  Principal и Role.

Role

Role (Роль) является набором разрешений (permission) для приложения.
Чтобы упростить я даю пример, приложение ABC имеет 2 роли  "EMPLOYEE" (сотрудние) и "MANAGER" (Менеджер).
  • Роль "EMPLOYEE" позволяет использовать функции продажи, и функции создания информации нового покупателя.
  • Роль "MANAGER" позволяет использовать функции менеджмента сотрудников, и смотреть отчет прибыли.

Principal

Principal можно временно понять как "Субъект" после того как вошли в систему, они имеют права сделать что-то в системе. Один "Субъект" может иметь один или много ролей. Это зависит от разрешения пользоваться приложением для разных пользователей.

3- Безопасность с Servlet Filter

В приложении  Java Servlet, один особенный  Servlet Filter используется для обработки безопасности, обычно называется  Security Filter.

Ниже является правило работы Security Filter.

Когда пользователь получает доступ в защищенную страницу (page), Security Filter проверит, если пользователь еще не вошел в систему, запрос пользователя будет перенаправлен (redirect) на страницу логина.
Если пользователь успешно вошел в систему, создается объект  Principal, он приносит информацию пользователя, включая все роли.
Если пользователь успешно вошел в систему до этого, и получил доступ в защищенную страницу (page). Security Filter проверит подходят ли роли пользователей для доступа в эту страницу или нет. Если недействительно, он отобразит страницу оповещающую запрет доступа (Access Denied) пользователю.

4- Цель примера

Это структура приложения, которую мы выполним:
Приложение включает 2 роли (Role) это  EMPLOYEE и  MANAGER.
  1. Роль EMPLOYEE позволяет иметь доступ в 2 страницы /userInfo и /employeeTask
  2. Роль MANAGER позволяет иметь доступ в 2 страницы /userInfo и /managerTask.
Все другие страницы в приложении не требуют логина.
Имеется 2 пользователя (user) это  employee1 и manager1.
  • Пользователю employee1 прикрепляется роль EMPLOYEE
  • Пользователю  manager1 прикрепляются 2 роли MANAGER и EMPLOYEE.
Пользователь может получить доступ ко всем незащищенным страницам как обыкновенно. Но если пользователь получает доступ в защищенную страницу ABC, она перенаправит (redirect) к странице логина. При успешном логине пользователя, случаются 2 ситуации:
  • Приложение перенаправит на страницу ABC после успешного логина, если userName имеет подходящую роль.
  • Приложение отобразит оповещение о запрете доступа (Access Denied) если userName имеет неподходящую роль.

5- Создать приложение

В Eclipse создайте  "Dynamic Web Project" с названием  SecurityWebApp, и конфигурируйте чтобы он работал на Tomcat Server. Я не буду детально говорить про шаги выполнения данных действий, вы можете просмотреть дополнительно в инструкции ниже:

6- UserAccount & DataDAO

Класс  UserAccount представляет пользователя приложения.
UserAccount.java
package org.o7planning.securitywebapp.bean;

import java.util.ArrayList;
import java.util.List;

public class UserAccount {
   public static final String GENDER_MALE = "M";
   public static final String GENDER_FEMALE = "F";

   private String userName;
   private String gender;
   private String password;

   private List<String> roles;

   public UserAccount() {

   }

   public UserAccount(String userName, String password, String gender, String... roles) {
      this.userName = userName;
      this.password = password;
      this.gender = gender;

      this.roles = new ArrayList<String>();
      if (roles != null) {
         for (String r : roles) {
            this.roles.add(r);
         }
      }
   }

   public String getUserName() {
      return userName;
   }

   public void setUserName(String userName) {
      this.userName = userName;
   }

   public String getGender() {
      return gender;
   }

   public void setGender(String gender) {
      this.gender = gender;
   }

   public String getPassword() {
      return password;
   }

   public void setPassword(String password) {
      this.password = password;
   }

   public List<String> getRoles() {
      return roles;
   }

   public void setRoles(List<String> roles) {
      this.roles = roles;
   }
}
Класс  DataDAO используется для запроса данных в базе данных (Симуляция).
DataDAO.java
package org.o7planning.securitywebapp.utils;

import java.util.HashMap;
import java.util.Map;

import org.o7planning.securitywebapp.bean.UserAccount;
import org.o7planning.securitywebapp.config.SecurityConfig;

public class DataDAO {

   private static final Map<String, UserAccount> mapUsers = new HashMap<String, UserAccount>();

   static {
      initUsers();
   }

   private static void initUsers() {

      // This user has a role as EMPLOYEE.
      UserAccount emp = new UserAccount("employee1", "123", UserAccount.GENDER_MALE, //
            SecurityConfig.ROLE_EMPLOYEE);

      // This user has 2 roles EMPLOYEE and MANAGER.
      UserAccount mng = new UserAccount("manager1", "123", UserAccount.GENDER_MALE, //
            SecurityConfig.ROLE_EMPLOYEE, SecurityConfig.ROLE_MANAGER);

      mapUsers.put(emp.getUserName(), emp);
      mapUsers.put(mng.getUserName(), mng);
   }

   // Find a User by userName and password.
   public static UserAccount findUser(String userName, String password) {
      UserAccount u = mapUsers.get(userName);
      if (u != null && u.getPassword().equals(password)) {
         return u;
      }
      return null;
   }

}

7- SecurityConfig & SecurityUtils

Класс  SecurityConfig помогает конфигурировать роли и функции (страниц) позволяющих имет доступ с той ролью.
SecurityConfig.java
package org.o7planning.securitywebapp.config;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class SecurityConfig {

	public static final String ROLE_MANAGER = "MANAGER";
	public static final String ROLE_EMPLOYEE = "EMPLOYEE";

	// String: Role
	// List<String>: urlPatterns.
	private static final Map<String, List<String>> mapConfig = new HashMap<String, List<String>>();

	static {
		init();
	}

	private static void init() {

		// Конфигурация для роли "EMPLOYEE".
		List<String> urlPatterns1 = new ArrayList<String>();

		urlPatterns1.add("/userInfo");
		urlPatterns1.add("/employeeTask");

		mapConfig.put(ROLE_EMPLOYEE, urlPatterns1);

		// Конфигурация для роли "MANAGER".
		List<String> urlPatterns2 = new ArrayList<String>();

		urlPatterns2.add("/userInfo");
		urlPatterns2.add("/managerTask");

		mapConfig.put(ROLE_MANAGER, urlPatterns2);
	}

	public static Set<String> getAllAppRoles() {
		return mapConfig.keySet();
	}

	public static List<String> getUrlPatternsForRole(String role) {
		return mapConfig.get(role);
	}

}
Класс  SecurityUtils является утилитарным классом, он имеет методы, помогающие проверить обязывает ли  request (запрос) выполнить логин или нет, и подходит ли тот  request с ролью пользователя вошедшего в систему или нет.
SecurityUtils.java
package org.o7planning.securitywebapp.utils;

import java.util.List;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;

import org.o7planning.securitywebapp.config.SecurityConfig;

public class SecurityUtils {

	// Проверить требует ли данный 'request' входа в систему или нет.
	public static boolean isSecurityPage(HttpServletRequest request) {
		String urlPattern = UrlPatternUtils.getUrlPattern(request);

		Set<String> roles = SecurityConfig.getAllAppRoles();

		for (String role : roles) {
			List<String> urlPatterns = SecurityConfig.getUrlPatternsForRole(role);
			if (urlPatterns != null && urlPatterns.contains(urlPattern)) {
				return true;
			}
		}
		return false;
	}

	// Проверить имеет ли данный 'request' подходящую роль?
	public static boolean hasPermission(HttpServletRequest request) {
		String urlPattern = UrlPatternUtils.getUrlPattern(request);

		Set<String> allRoles = SecurityConfig.getAllAppRoles();

		for (String role : allRoles) {
			if (!request.isUserInRole(role)) {
				continue;
			}
			List<String> urlPatterns = SecurityConfig.getUrlPatternsForRole(role);
			if (urlPatterns != null && urlPatterns.contains(urlPattern)) {
				return true;
			}
		}
		return false;
	}
}
UrlPatternUtils.java
package org.o7planning.securitywebapp.utils;

import java.util.Collection;
import java.util.Map;

import javax.servlet.ServletContext;
import javax.servlet.ServletRegistration;
import javax.servlet.http.HttpServletRequest;

public class UrlPatternUtils {

   private static boolean hasUrlPattern(ServletContext servletContext, String urlPattern) {

      Map<String, ? extends ServletRegistration> map = servletContext.getServletRegistrations();

      for (String servletName : map.keySet()) {
         ServletRegistration sr = map.get(servletName);

         Collection<String> mappings = sr.getMappings();
         if (mappings.contains(urlPattern)) {
            return true;
         }

      }
      return false;
   }

   // servletPath:
   // ==> /spath
   // ==> /spath/*
   // ==> *.ext
   // ==> /
   public static String getUrlPattern(HttpServletRequest request) {
      ServletContext servletContext = request.getServletContext();
      String servletPath = request.getServletPath();
      String pathInfo = request.getPathInfo();

      String urlPattern = null;
      if (pathInfo != null) {
         urlPattern = servletPath + "/*";
         return urlPattern;
      }
      urlPattern = servletPath;

      boolean has = hasUrlPattern(servletContext, urlPattern);
      if (has) {
         return urlPattern;
      }
      int i = servletPath.lastIndexOf('.');
      if (i != -1) {
         String ext = servletPath.substring(i + 1);
         urlPattern = "*." + ext;
         has = hasUrlPattern(servletContext, urlPattern);

         if (has) {
            return urlPattern;
         }
      }
      return "/";
   }
}

8- SecurityFilter

SecurityFilter является  Servlet Filter, который выполняет обязанность проверки всех  request перед тем как позволить получить доступ в защищенные страницы (page).

SecurityFilter читает  "конфигурации безопасности" объявленные в классе  SecurityConfig.
SecurityFilter.java
package org.o7planning.securitywebapp.filter;

import java.io.IOException;
import java.util.List;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.o7planning.securitywebapp.bean.UserAccount;
import org.o7planning.securitywebapp.request.UserRoleRequestWrapper;
import org.o7planning.securitywebapp.utils.AppUtils;
import org.o7planning.securitywebapp.utils.SecurityUtils;

@WebFilter("/*")
public class SecurityFilter implements Filter {

	public SecurityFilter() {
	}

	@Override
	public void destroy() {
	}

	@Override
	public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
			throws IOException, ServletException {
		HttpServletRequest request = (HttpServletRequest) req;
		HttpServletResponse response = (HttpServletResponse) resp;

		String servletPath = request.getServletPath();

		// Информация пользователя сохранена в Session
		// (После успешного входа в систему).
		UserAccount loginedUser = AppUtils.getLoginedUser(request.getSession());

		if (servletPath.equals("/login")) {
			chain.doFilter(request, response);
			return;
		}
		HttpServletRequest wrapRequest = request;

		if (loginedUser != null) {
			// User Name
			String userName = loginedUser.getUserName();

			// Роли (Role).
			List<String> roles = loginedUser.getRoles();

			// Старый пакет request с помощью нового Request с информацией userName и Roles.
			wrapRequest = new UserRoleRequestWrapper(userName, roles, request);
		}

		// Страницы требующие входа в систему.
		if (SecurityUtils.isSecurityPage(request)) {

			// Если пользователь еще не вошел в систему,
			// Redirect (перенаправить) к странице логина.
			if (loginedUser == null) {

				String requestUri = request.getRequestURI();

				// Сохранить текущую страницу для перенаправления (redirect) после успешного входа в систему.
				int redirectId = AppUtils.storeRedirectAfterLoginUrl(request.getSession(), requestUri);

				response.sendRedirect(wrapRequest.getContextPath() + "/login?redirectId=" + redirectId);
				return;
			}

			// Проверить пользователь имеет действительную роль или нет?
			boolean hasPermission = SecurityUtils.hasPermission(wrapRequest);
			if (!hasPermission) {

				RequestDispatcher dispatcher //
						= request.getServletContext().getRequestDispatcher("/WEB-INF/views/accessDeniedView.jsp");

				dispatcher.forward(request, response);
				return;
			}
		}

		chain.doFilter(wrapRequest, response);
	}

	@Override
	public void init(FilterConfig fConfig) throws ServletException {

	}

}
UserRoleRequestWrapper.java
package org.o7planning.securitywebapp.request;

import java.security.Principal;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

/**
 * An extension for the HTTPServletRequest that overrides the getUserPrincipal()
 * and isUserInRole(). We supply these implementations here, where they are not
 * normally populated unless we are going through the facility provided by the
 * container.
 * <p>
 * If he user or roles are null on this wrapper, the parent request is consulted
 * to try to fetch what ever the container has set for us. This is intended to
 * be created and used by the UserRoleFilter.
 * 
 * @author thein
 *
 */
public class UserRoleRequestWrapper extends HttpServletRequestWrapper {

	private String user;
	private List<String> roles = null;
	private HttpServletRequest realRequest;

	public UserRoleRequestWrapper(String user, List<String> roles, HttpServletRequest request) {
		super(request);
		this.user = user;
		this.roles = roles;
		this.realRequest = request;
	}

	@Override
	public boolean isUserInRole(String role) {
		if (roles == null) {
			return this.realRequest.isUserInRole(role);
		}
		return roles.contains(role);
	}

	@Override
	public Principal getUserPrincipal() {
		if (this.user == null) {
			return realRequest.getUserPrincipal();
		}

		// Make an anonymous implementation to just return our user
		return new Principal() {
			@Override
			public String getName() {
				return user;
			}
		};
	}
}

9- Home Page, Login, Logout

HomeServlet.java
package org.o7planning.securitywebapp.servlet;

import java.io.IOException;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet({ "/", "/index" })
public class HomeServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    public HomeServlet() {
        super();
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        RequestDispatcher dispatcher //
                = this.getServletContext().getRequestDispatcher("/WEB-INF/views/homeView.jsp");

        dispatcher.forward(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        doGet(request, response);
    }

}

 
LoginServlet.java
package org.o7planning.securitywebapp.servlet;

import java.io.IOException;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.o7planning.securitywebapp.bean.UserAccount;
import org.o7planning.securitywebapp.utils.AppUtils;
import org.o7planning.securitywebapp.utils.DataDAO;

@WebServlet("/login")
public class LoginServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	public LoginServlet() {
		super();
	}

	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		RequestDispatcher dispatcher //
				= this.getServletContext().getRequestDispatcher("/WEB-INF/views/loginView.jsp");

		dispatcher.forward(request, response);
	}

	@Override
	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		String userName = request.getParameter("userName");
		String password = request.getParameter("password");
		UserAccount userAccount = DataDAO.findUser(userName, password);

		if (userAccount == null) {
			String errorMessage = "Invalid userName or Password";

			request.setAttribute("errorMessage", errorMessage);

			RequestDispatcher dispatcher //
					= this.getServletContext().getRequestDispatcher("/WEB-INF/views/loginView.jsp");

			dispatcher.forward(request, response);
			return;
		}

		AppUtils.storeLoginedUser(request.getSession(), userAccount);

		// 
		int redirectId = -1;
		try {
			redirectId = Integer.parseInt(request.getParameter("redirectId"));
		} catch (Exception e) {
		}
		String requestUri = AppUtils.getRedirectAfterLoginUrl(request.getSession(), redirectId);
		if (requestUri != null) {
			response.sendRedirect(requestUri);
		} else {
			// По умолчанию после успешного входа в систему
			// перенаправить на страницу /userInfo
			response.sendRedirect(request.getContextPath() + "/userInfo");
		}

	}

}
AppUtils.java
package org.o7planning.securitywebapp.utils;

import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpSession;

import org.o7planning.securitywebapp.bean.UserAccount;

public class AppUtils {

	private static int REDIRECT_ID = 0;

	private static final Map<Integer, String> id_uri_map = new HashMap<Integer, String>();
	private static final Map<String, Integer> uri_id_map = new HashMap<String, Integer>();

	// Сохранить информацию пользователя в Session.
	public static void storeLoginedUser(HttpSession session, UserAccount loginedUser) {
		// На JSP можно получить доступ через ${loginedUser}
		session.setAttribute("loginedUser", loginedUser);
	}

	// Получить информацию пользователя, сохраненную в Session.
	public static UserAccount getLoginedUser(HttpSession session) {
		UserAccount loginedUser = (UserAccount) session.getAttribute("loginedUser");
		return loginedUser;
	}

	public static int storeRedirectAfterLoginUrl(HttpSession session, String requestUri) {
		Integer id = uri_id_map.get(requestUri);

		if (id == null) {
			id = REDIRECT_ID++;

			uri_id_map.put(requestUri, id);
			id_uri_map.put(id, requestUri);
			return id;
		}

		return id;
	}

	public static String getRedirectAfterLoginUrl(HttpSession session, int redirectId) {
		String url = id_uri_map.get(redirectId);
		if (url != null) {
			return url;
		}
		return null;
	}

}
LogoutServlet.java
package org.o7planning.securitywebapp.servlet;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/logout")
public class LogoutServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	public LogoutServlet() {
		super();
	}

	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		request.getSession().invalidate();

		// Redrect to Home Page.
		response.sendRedirect(request.getContextPath() + "/");

	}

	@Override
	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		this.doGet(request, response);
	}

}
UserInfoServlet.java
package org.o7planning.securitywebapp.servlet;

import java.io.IOException;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/userInfo")
public class UserInfoServlet extends HttpServlet {
   private static final long serialVersionUID = 1L;

   public UserInfoServlet() {
      super();
   }

   @Override
   protected void doGet(HttpServletRequest request, HttpServletResponse response)
         throws ServletException, IOException {

      RequestDispatcher dispatcher //
            = this.getServletContext().getRequestDispatcher("/WEB-INF/views/userInfoView.jsp");

      dispatcher.forward(request, response);
   }

   @Override
   protected void doPost(HttpServletRequest request, HttpServletResponse response)
         throws ServletException, IOException {
      
      doGet(request, response);
   }

}
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns="http://java.sun.com/xml/ns/javaee"
      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
                        http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
      id="WebApp_ID" version="3.0">
      
  <display-name>SecurityWebApp</display-name>
 
 
  <welcome-file-list>
 
    <welcome-file>/</welcome-file>
     
  </welcome-file-list>
 
 
</web-app>
/WEB-INF/views/_menu.jsp
<a href="${pageContext.request.contextPath}/employeeTask">
  Employee Task
</a>
||
<a href="${pageContext.request.contextPath}/managerTask">
  Manager Task
</a>
||
<a href="${pageContext.request.contextPath}/userInfo">
  User Info
</a>       
||
<a href="${pageContext.request.contextPath}/login">
  Login
</a>
||
<a href="${pageContext.request.contextPath}/logout">
  Logout
</a>

&nbsp;
<span style="color:red">[ ${loginedUser.userName} ]</span>
/WEB-INF/views/homeView.jsp
<!DOCTYPE html>
<html>
   <head>
      <meta charset="UTF-8">
      <title>Home Page</title>
   </head>
   <body>
   
      <jsp:include page="_menu.jsp"></jsp:include>
   
      <h3>Home Page</h3>
            
   </body>
</html>
/WEB-INF/views/loginView.jsp
<!DOCTYPE html>
<html>
   <head>
      <meta charset="UTF-8">
      <title>Login</title>
   </head>
   <body>

      <jsp:include page="_menu.jsp"></jsp:include>   

      <h3>Login Page</h3>

      <p style="color: red;">${errorString}</p>

      <form method="POST" action="${pageContext.request.contextPath}/login">
         <input type="hidden" name="redirectId" value="${param.redirectId}" />
         <table border="0">
            <tr>
               <td>User Name</td>
               <td><input type="text" name="userName" value= "${user.userName}" /> </td>
            </tr>
            <tr>
               <td>Password</td>
               <td><input type="password" name="password" value= "${user.password}" /> </td>
            </tr>
         
            <tr>
               <td colspan ="2">
                  <input type="submit" value= "Submit" />
                  <a href="${pageContext.request.contextPath}/">Cancel</a>
               </td>
            </tr>
         </table>
      </form>

      <p style="color:blue;">Login with:</p>
      
      employee1/123 <br>
      manager1/123
     
 

   </body>
</html>
/WEB-INF/views/userInfoView.jsp
<!DOCTYPE html>
<html>
   <head>
      <meta charset="UTF-8">
      <title>User Info</title>
   </head>
   <body>

     <jsp:include page="_menu.jsp"></jsp:include>

      <h3>Hello: ${loginedUser.userName}</h3>

      User Name: <b>${loginedUser.userName}</b>
      <br />
      Gender: ${loginedUser.gender } <br />


   </body>
</html>

Запуск приложения:

10- Страницы требующие логин.

EmployeeTaskServlet.java
package org.o7planning.securitywebapp.servlet;

import java.io.IOException;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/employeeTask")
public class EmployeeTaskServlet extends HttpServlet {
   private static final long serialVersionUID = 1L;

   public EmployeeTaskServlet() {
      super();
   }

   @Override
   protected void doGet(HttpServletRequest request, HttpServletResponse response)
         throws ServletException, IOException {

      RequestDispatcher dispatcher //
            = this.getServletContext()//
                  .getRequestDispatcher("/WEB-INF/views/employeeTaskView.jsp");

      dispatcher.forward(request, response);
   }

   @Override
   protected void doPost(HttpServletRequest request, HttpServletResponse response)
         throws ServletException, IOException {

      doGet(request, response);
   }

}
ManagerTaskServlet.java
package org.o7planning.securitywebapp.servlet;

import java.io.IOException;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/managerTask")
public class ManagerTaskServlet extends HttpServlet {
   private static final long serialVersionUID = 1L;

   public ManagerTaskServlet() {
      super();
   }

   @Override
   protected void doGet(HttpServletRequest request, HttpServletResponse response)
         throws ServletException, IOException {

      RequestDispatcher dispatcher //
            = this.getServletContext()//
                  .getRequestDispatcher("/WEB-INF/views/managerTaskView.jsp");

      dispatcher.forward(request, response);
   }

   @Override
   protected void doPost(HttpServletRequest request, HttpServletResponse response)
         throws ServletException, IOException {

      doGet(request, response);
   }

}
/WEB-INF/views/employeeTaskView.jsp
<!DOCTYPE html>
<html>
   <head>
      <meta charset="UTF-8">
      <title>Employee Task</title>
   </head>
   <body>
  
      <jsp:include page="_menu.jsp"></jsp:include>
      
      <h3>Employee Task</h3>
      
      Hello, This is a protected page!
      
   </body>
</html>
/WEB-INF/views/managerTaskView.jsp
<!DOCTYPE html>
<html>
   <head>
      <meta charset="UTF-8">
      <title>Manager Task</title>
   </head>
   
   <body>
   
      <jsp:include page="_menu.jsp"></jsp:include>
      
      <h3>Manager Task</h3>
      
      Hello, This is a protected page!
      
   </body>
</html>
/WEB-INF/views/accessDenied.jsp
<!DOCTYPE html>
<html>
   <head>
      <meta charset="UTF-8">
      <title>Access Denied</title>
   </head>
   <body>
   
      <jsp:include page="_menu.jsp"></jsp:include>
   
      <br/><br/>
      
      <h3 style="color:red;">Access Denied!</h3>
            
   </body>
</html>

Запуск приложения:

Запустить приложение и войти в систему с userName = "employee1", это пользователь с ролью  "EMPLOYEE".
Запустить приложение и войти в систему с userName = "manager1", это пользователь с 2-мя ролями  "EMPLOYEE" и "MANAGER".