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:
parent
cb65018f66
commit
f74400ee6e
|
@ -0,0 +1,5 @@
|
||||||
|
## Servlets
|
||||||
|
|
||||||
|
This module contains articles about Servlets.
|
||||||
|
|
||||||
|
### Relevant Articles:
|
|
@ -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>
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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("./");
|
||||||
|
}
|
||||||
|
}
|
|
@ -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");
|
||||||
|
}
|
||||||
|
}
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
2
pom.xml
2
pom.xml
|
@ -459,6 +459,7 @@
|
||||||
<module>java-vavr-stream</module>
|
<module>java-vavr-stream</module>
|
||||||
<module>java-websocket</module>
|
<module>java-websocket</module>
|
||||||
<module>javax-servlets</module>
|
<module>javax-servlets</module>
|
||||||
|
<module>javax-servlets-2</module>
|
||||||
<module>javaxval</module>
|
<module>javaxval</module>
|
||||||
<module>jaxb</module>
|
<module>jaxb</module>
|
||||||
<module>jee-7</module>
|
<module>jee-7</module>
|
||||||
|
@ -943,6 +944,7 @@
|
||||||
<module>java-vavr-stream</module>
|
<module>java-vavr-stream</module>
|
||||||
<module>java-websocket</module>
|
<module>java-websocket</module>
|
||||||
<module>javax-servlets</module>
|
<module>javax-servlets</module>
|
||||||
|
<module>javax-servlets-2</module>
|
||||||
<module>javaxval</module>
|
<module>javaxval</module>
|
||||||
<module>jaxb</module>
|
<module>jaxb</module>
|
||||||
<module>jee-7</module>
|
<module>jee-7</module>
|
||||||
|
|
Loading…
Reference in New Issue