BAEL-2080 - Check if a user is logged-in with Servlets and JSP (#11821)

* BAEL-2080 - Check if a user is logged-in with Servlets and JSP

* new module: javax-servlets-2

* adding javax-servlets-2 to the parent pom.

* adding module javax-servlets-2 to all profiles
This commit is contained in:
Ulisses Lima 2022-02-25 03:36:17 -03:00 committed by GitHub
parent cb65018f66
commit f74400ee6e
12 changed files with 478 additions and 0 deletions

View File

@ -0,0 +1,5 @@
## Servlets
This module contains articles about Servlets.
### Relevant Articles:

60
javax-servlets-2/pom.xml Normal file
View File

@ -0,0 +1,60 @@
<?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.baeldung.javax-servlets</groupId>
<artifactId>javax-servlets-2</artifactId>
<version>1.0-SNAPSHOT</version>
<name>javax-servlets-2</name>
<packaging>war</packaging>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>parent-modules</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<dependencies>
<!-- File Uploading -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>${commons-fileupload.version}</version>
</dependency>
<!-- Servlet -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>${javax.servlet-api.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>${javax.servlet.jsp-api.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>${jstl.version}</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>${org.apache.httpcomponents.version}</version>
<scope>test</scope>
<exclusions>
<exclusion>
<artifactId>commons-logging</artifactId>
<groupId>commons-logging</groupId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<properties>
<org.apache.httpcomponents.version>4.5.13</org.apache.httpcomponents.version>
<javax.servlet-api.version>4.0.1</javax.servlet-api.version>
</properties>
</project>

View File

@ -0,0 +1,80 @@
package com.baeldung.user.check;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
/**
* @since 6 de fev de 2022
* @author ulisses
*/
public class User implements Serializable {
private static final long serialVersionUID = 1L;
protected static final HashMap<String, User> DB = new HashMap<>();
static {
DB.put("admin", new User("admin", "password"));
DB.put("user", new User("user", "pass"));
}
private String name;
private String password;
private List<Date> logins = new ArrayList<Date>();
public User(String name, String password) {
this.name = name;
this.password = password;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Date> getLogins() {
return logins;
}
public void setLogins(List<Date> logins) {
this.logins = logins;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
User other = (User) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}

View File

@ -0,0 +1,46 @@
package com.baeldung.user.check;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
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;
@WebFilter("/user-check/*")
public class UserCheckFilter implements Filter {
public static void forward(HttpServletRequest request, HttpServletResponse response, String page) throws ServletException, IOException {
request.getRequestDispatcher("/WEB-INF/user.check" + page)
.forward(request, response);
}
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
if (!(req instanceof HttpServletRequest)) {
throw new ServletException("Can only process HttpServletRequest");
}
if (!(res instanceof HttpServletResponse)) {
throw new ServletException("Can only process HttpServletResponse");
}
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
request.setAttribute("origin", request.getRequestURI());
if (!request.getRequestURI()
.contains("login") && request.getSession(false) == null) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
forward(request, response, "/login.jsp");
// we return here so the original servlet is not processed
return;
}
chain.doFilter(request, response);
}
}

View File

@ -0,0 +1,56 @@
package com.baeldung.user.check;
import java.io.IOException;
import java.util.Date;
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 javax.servlet.http.HttpSession;
@WebServlet("/user-check/login")
public class UserCheckLoginServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
if (request.getSession(false) != null) {
response.sendRedirect(request.getContextPath() + "/user-check/home");
return;
}
String referer = (String) request.getAttribute("origin");
request.setAttribute("origin", referer);
UserCheckFilter.forward(request, response, "/login.jsp");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String key = request.getParameter("name");
String pass = request.getParameter("password");
User user = User.DB.get(key);
if (user == null || !user.getPassword()
.equals(pass)) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
request.setAttribute("origin", request.getParameter("origin"));
request.setAttribute("error", "invalid login");
UserCheckFilter.forward(request, response, "/login.jsp");
return;
}
user.getLogins()
.add(new Date());
HttpSession session = request.getSession();
session.setAttribute("user", user);
String origin = request.getParameter("origin");
if (origin == null || origin.contains("login"))
origin = "./";
response.sendRedirect(origin);
}
}

View File

@ -0,0 +1,26 @@
package com.baeldung.user.check;
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;
import javax.servlet.http.HttpSession;
@WebServlet("/user-check/logout")
public class UserCheckLogoutServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
HttpSession session = request.getSession(false);
if (session != null) {
session.invalidate();
}
request.setAttribute("loggedOut", true);
response.sendRedirect("./");
}
}

View File

@ -0,0 +1,28 @@
package com.baeldung.user.check;
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;
import javax.servlet.http.HttpSession;
@WebServlet(name = "home", urlPatterns = { "/user-check/", "/user-check", "/user-check/home" })
public class UserCheckServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
HttpSession session = request.getSession(false);
if (session == null || session.getAttribute("user") == null) {
throw new IllegalStateException("user not logged in");
}
User user = (User) session.getAttribute("user");
request.setAttribute("user", user);
UserCheckFilter.forward(request, response, "/home.jsp");
}
}

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
</configuration>

View File

@ -0,0 +1,31 @@
<%@ page contentType="text/html;charset=UTF-8" session="false"%>
<%@ taglib uri="http://java.sun.com/jstl/core_rt" prefix="c"%>
<html>
<head>
<title>login success - current session info</title>
</head>
<body>
<section>
<h2>user info</h2>
<div>
<span>name: ${user.name}</span>
</div>
<div>
<span>logins:</span>
<ul>
<c:forEach var="login" items="${user.logins}">
<li>${login}</li>
</c:forEach>
</ul>
</div>
<div>
<a href="${pageContext.request.contextPath}/user-check/logout">
logout
</a>
</div>
</section>
</body>
</html>

View File

@ -0,0 +1,33 @@
<%@ page contentType="text/html;charset=UTF-8" session="false"%>
<%@ taglib uri="http://java.sun.com/jstl/core_rt" prefix="c"%>
<html>
<head>
<title>login</title>
</head>
<body>
<form action="${pageContext.request.contextPath}/user-check/login"
method="POST">
<input type="hidden" name="origin" value="${origin}">
<c:if test="${not empty origin}">
<div>* redirected to login from: ${origin}</div>
</c:if>
<c:if test="${not empty error}">
<div>* error: ${error}</div>
</c:if>
<fieldset>
<legend>credentials</legend>
<label for="name">name</label>
<input type="text" name="name">
<label for="password">password</label>
<input type="password" name="password">
<input type="submit">
</fieldset>
</form>
</body>
</html>

View File

@ -0,0 +1,98 @@
package com.baeldung.user.check;
import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.LaxRedirectStrategy;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class UserCheckServletLiveTest {
private static final String BASE_URL = "http://localhost:8080/javax-servlets-2/user-check";
@Mock
HttpServletRequest request;
@Mock
HttpServletResponse response;
private CloseableHttpClient buildClient() {
return HttpClientBuilder.create()
.setRedirectStrategy(new LaxRedirectStrategy())
.build();
}
@Test
public void whenCorrectCredentials_thenLoginSucceeds() throws Exception {
try (CloseableHttpClient client = buildClient()) {
HttpPost post = new HttpPost(BASE_URL + "/login");
List<BasicNameValuePair> form = new ArrayList<>();
form.add(new BasicNameValuePair("name", "admin"));
form.add(new BasicNameValuePair("password", "password"));
post.setEntity(new UrlEncodedFormEntity(form));
try (CloseableHttpResponse response = client.execute(post)) {
String body = EntityUtils.toString(response.getEntity());
assertTrue(response.getStatusLine()
.getStatusCode() == 200);
assertTrue(body.contains("login success"));
}
}
}
@Test
public void whenIncorrectCredentials_thenLoginFails() throws Exception {
try (CloseableHttpClient client = buildClient()) {
HttpPost post = new HttpPost(BASE_URL + "/login");
List<BasicNameValuePair> form = new ArrayList<>();
form.add(new BasicNameValuePair("name", "admin"));
form.add(new BasicNameValuePair("password", "invalid"));
post.setEntity(new UrlEncodedFormEntity(form));
try (CloseableHttpResponse response = client.execute(post)) {
String body = EntityUtils.toString(response.getEntity());
assertTrue(response.getStatusLine()
.getStatusCode() == 401);
assertTrue(body.contains("invalid login"));
}
}
}
@Test
public void whenNotLoggedIn_thenRedirectedToLoginPage() throws Exception {
try (CloseableHttpClient client = buildClient()) {
HttpGet get = new HttpGet(BASE_URL + "/home");
try (CloseableHttpResponse response = client.execute(get)) {
String body = EntityUtils.toString(response.getEntity());
assertTrue(response.getStatusLine()
.getStatusCode() == 401);
assertTrue(body.contains("redirected to login"));
}
}
}
}

View File

@ -459,6 +459,7 @@
<module>java-vavr-stream</module>
<module>java-websocket</module>
<module>javax-servlets</module>
<module>javax-servlets-2</module>
<module>javaxval</module>
<module>jaxb</module>
<module>jee-7</module>
@ -943,6 +944,7 @@
<module>java-vavr-stream</module>
<module>java-websocket</module>
<module>javax-servlets</module>
<module>javax-servlets-2</module>
<module>javaxval</module>
<module>jaxb</module>
<module>jee-7</module>