mirror of
https://github.com/kmitresse/Cards-Rush.git
synced 2026-05-14 01:21:49 +00:00
feat: dev-web - forgotten password management
This commit is contained in:
@@ -44,12 +44,15 @@ CREATE TABLE IF NOT EXISTS player
|
||||
FOREIGN KEY (user_id) REFERENCES `user` (id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS recovery_password_token(
|
||||
-- Table: RecoveryPasswordToken
|
||||
CREATE TABLE IF NOT EXISTS recovery_password_token
|
||||
(
|
||||
id INT NOT NULL AUTO_INCREMENT,
|
||||
email VARCHAR(255) NOT NULL,
|
||||
user_id INT NOT NULL,
|
||||
token VARCHAR(255) NOT NULL,
|
||||
expires_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (id)
|
||||
PRIMARY KEY (id),
|
||||
FOREIGN KEY (user_id) REFERENCES `user` (id)
|
||||
);
|
||||
|
||||
DELIMITER //
|
||||
|
||||
@@ -45,6 +45,11 @@ public abstract class GameDAOFactory {
|
||||
*/
|
||||
public abstract DAO<Player> getDAOPlayer() throws DAOException;
|
||||
|
||||
/**
|
||||
* @return le DAO pour la classe/table RecoveryPasswordToken
|
||||
* @throws DAOException en cas de problème
|
||||
* @see RecoveryPasswordToken
|
||||
*/
|
||||
public abstract DAO<RecoveryPasswordToken> getDAORecoveryPasswordToken() throws DAOException;
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ import uppa.project.pojo.RecoveryPasswordToken;
|
||||
import uppa.project.provider.EntityManagerProvider;
|
||||
|
||||
/**
|
||||
* DAO pour les utilisateurs
|
||||
* DAO pour les tokens de récupération de mot de passe
|
||||
*
|
||||
* @author Kévin Mitresse
|
||||
* @author Lucàs Vabre
|
||||
|
||||
@@ -5,6 +5,8 @@ import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.persistence.Temporal;
|
||||
import jakarta.persistence.TemporalType;
|
||||
@@ -24,10 +26,13 @@ public class RecoveryPasswordToken {
|
||||
@Column(name = "id")
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private int id;
|
||||
|
||||
@Column(name = "token")
|
||||
private String token;
|
||||
@Column(name = "email")
|
||||
private String email;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "user_id", nullable = false)
|
||||
private User user;
|
||||
|
||||
@Temporal(TemporalType.TIMESTAMP)
|
||||
@Column(name = "expires_at")
|
||||
@@ -38,24 +43,27 @@ public class RecoveryPasswordToken {
|
||||
|
||||
/**
|
||||
* Constructeur
|
||||
*
|
||||
* @param token
|
||||
* @param email
|
||||
* @param user
|
||||
*/
|
||||
public RecoveryPasswordToken(String token, String email) {
|
||||
public RecoveryPasswordToken(String token, User user) {
|
||||
this.token = token;
|
||||
this.email = email;
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructeur depuis la base de données
|
||||
*
|
||||
* @param id
|
||||
* @param token
|
||||
* @param email
|
||||
* @param user
|
||||
*/
|
||||
public RecoveryPasswordToken(int id, String token, String email) {
|
||||
public RecoveryPasswordToken(int id, String token, User user, Date expiresAt) {
|
||||
this.id = id;
|
||||
this.token = token;
|
||||
this.email = email;
|
||||
this.user = user;
|
||||
this.expiresAt = expiresAt;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -86,21 +94,21 @@ public class RecoveryPasswordToken {
|
||||
}
|
||||
|
||||
/**
|
||||
* Récupère l'email associé au token
|
||||
* Récupère l'utilisateur associé au token
|
||||
*
|
||||
* @return l'email associé au token
|
||||
* @return l'utilisateur associé au token
|
||||
*/
|
||||
public String getEmail() {
|
||||
return email;
|
||||
public User getUser() {
|
||||
return user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Définit l'email associé au token
|
||||
* Définit l'utilisateur associé au token
|
||||
*
|
||||
* @param email
|
||||
* @param user
|
||||
*/
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
public void setUser(User user) {
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -120,4 +128,23 @@ public class RecoveryPasswordToken {
|
||||
public void setExpiresAt(Date expiresAt) {
|
||||
this.expiresAt = expiresAt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "RecoveryPasswordToken{" +
|
||||
"id=" + id +
|
||||
", token='" + token + '\'' +
|
||||
", user=" + user +
|
||||
", expiresAt=" + expiresAt +
|
||||
'}';
|
||||
}
|
||||
|
||||
/**
|
||||
* Récupère la date d'expiration du token
|
||||
*
|
||||
* @return la date d'expiration du token
|
||||
*/
|
||||
public Date getExpirationDate() {
|
||||
return expiresAt;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
|
||||
package uppa.project.pojo;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import jakarta.persistence.CascadeType;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
@@ -42,21 +41,30 @@ public class User implements Serializable {
|
||||
@Column(name = "id")
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private BigDecimal id;
|
||||
|
||||
@Column(name = "username")
|
||||
private String username;
|
||||
|
||||
@Column(name = "email")
|
||||
private String email;
|
||||
|
||||
@Column(name = "password")
|
||||
private String password;
|
||||
|
||||
@Temporal(TemporalType.DATE)
|
||||
@Column(name = "birth")
|
||||
private Date birth;
|
||||
|
||||
@Column(name = "gender")
|
||||
@Enumerated(EnumType.STRING)
|
||||
private Gender gender;
|
||||
|
||||
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
|
||||
private Set<Player> playedGame;
|
||||
|
||||
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
|
||||
private Set<RecoveryPasswordToken> recoveryPasswordTokens;
|
||||
|
||||
/**
|
||||
* Constructeur par défaut
|
||||
*/
|
||||
|
||||
@@ -31,11 +31,6 @@ public class ForgottenPasswordServlet extends HttpServlet {
|
||||
|
||||
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
|
||||
|
||||
if (request.getSession().getAttribute("user") != null) {
|
||||
response.sendRedirect(request.getContextPath() + "/main-menu");
|
||||
return;
|
||||
}
|
||||
|
||||
request.getRequestDispatcher("/WEB-INF/views/forgotten-password.jsp").forward(request, response);
|
||||
}
|
||||
|
||||
@@ -53,18 +48,9 @@ public class ForgottenPasswordServlet extends HttpServlet {
|
||||
response.sendRedirect(request.getContextPath() + "/forgotten-password?error=1");
|
||||
} else {
|
||||
String token = UUID.randomUUID().toString();
|
||||
System.out.println("Token : " + token);
|
||||
System.out.println("1");
|
||||
RecoveryPasswordToken recoveryPasswordToken = new RecoveryPasswordToken(token, user.getEmail());
|
||||
Game_JPA_DAO_Factory jpaDaoFactory = new Game_JPA_DAO_Factory();
|
||||
try {
|
||||
System.out.println("2");
|
||||
DAO<RecoveryPasswordToken> daoJpaRecoveryPasswordToken = jpaDaoFactory.getDAORecoveryPasswordToken();
|
||||
System.out.println("3");
|
||||
daoJpaRecoveryPasswordToken.create(recoveryPasswordToken);
|
||||
} catch (DAOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
RecoveryPasswordToken recoveryPasswordToken = new RecoveryPasswordToken(token, user);
|
||||
CreateToken(recoveryPasswordToken);
|
||||
sendRecoveryEmail(email, token);
|
||||
response.sendRedirect(request.getContextPath() + "/forgotten-password?success=200");
|
||||
}
|
||||
@@ -80,9 +66,12 @@ public class ForgottenPasswordServlet extends HttpServlet {
|
||||
public void sendRecoveryEmail(String email, String token) {
|
||||
|
||||
String host = "smtp.gmail.com";
|
||||
String port = "587";
|
||||
String username = System.getenv("MAIL_USERNAME");
|
||||
String password = System.getenv("MAIL_PASSWORD");
|
||||
String port = "587";
|
||||
//TODO: Set up environment variables
|
||||
// String username = System.getenv("MAIL_USERNAME");
|
||||
// String password = System.getenv("MAIL_PASSWORD");
|
||||
String username = "kmitresse@gmail.com";
|
||||
String password = "xwos ujwf cesq ocyt";
|
||||
|
||||
Properties props = new Properties();
|
||||
props.put("mail.smtp.auth", "true");
|
||||
@@ -105,7 +94,7 @@ public class ForgottenPasswordServlet extends HttpServlet {
|
||||
message.setSubject("Réinitialisation de votre mot de passe");
|
||||
message.setText("Bonjour,\n\n" +
|
||||
"Vous avez demandé la réinitialisation de votre mot de passe.\n" +
|
||||
"Pour cela, veuillez cliquer sur le lien suivant : http://localhost:8080/reset-password?token=" + token + "\n\n" +
|
||||
"Pour cela, veuillez cliquer sur le lien suivant : http://localhost:8088/project_war_exploded/reset-password?token=" + token + "\n\n" +
|
||||
"Cordialement,\n" +
|
||||
"L'équipe CardRush");
|
||||
// Envoi du message
|
||||
@@ -128,8 +117,16 @@ public class ForgottenPasswordServlet extends HttpServlet {
|
||||
} catch (DAOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
}
|
||||
public static void CreateToken(RecoveryPasswordToken token){
|
||||
Game_JPA_DAO_Factory jpaDaoFactory = new Game_JPA_DAO_Factory();
|
||||
try {
|
||||
DAO<RecoveryPasswordToken> daoJpaRecoveryPasswordToken = jpaDaoFactory.getDAORecoveryPasswordToken();
|
||||
daoJpaRecoveryPasswordToken.create(token);
|
||||
} catch (DAOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
}
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
package uppa.project.servlet;
|
||||
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.annotation.WebServlet;
|
||||
import jakarta.servlet.http.HttpServlet;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import uppa.project.dao.DAOException;
|
||||
import uppa.project.dao.jpa.DAO_JPA_RecoveryPasswordToken;
|
||||
import uppa.project.dao.jpa.DAO_JPA_User;
|
||||
import uppa.project.pojo.RecoveryPasswordToken;
|
||||
import uppa.project.pojo.User;
|
||||
|
||||
@WebServlet(name = "resetPasswordServlet", value = "/reset-password")
|
||||
public class ResetPasswordServlet extends HttpServlet {
|
||||
public void init() {
|
||||
}
|
||||
|
||||
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
|
||||
|
||||
RecoveryPasswordToken recoveryPasswordToken = findRecoveryToken(request.getParameter("token"));
|
||||
if (recoveryPasswordToken == null) {
|
||||
response.sendRedirect(request.getContextPath() + "/error?code=404");
|
||||
return;
|
||||
}
|
||||
request.getRequestDispatcher("/WEB-INF/views/reset-password.jsp").forward(request, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gestion de la réinitialisation de mot de passe
|
||||
*
|
||||
* @param request
|
||||
* @param response
|
||||
* @throws IOException
|
||||
*/
|
||||
public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||
RecoveryPasswordToken recoveryPasswordToken = findRecoveryToken(request.getParameter("token"));
|
||||
User user = recoveryPasswordToken.getUser();
|
||||
String newPassword = request.getParameter("newPassword");
|
||||
String confirmPassword = request.getParameter("confirmPassword");
|
||||
System.out.println("newPassword: " + newPassword);
|
||||
System.out.println("confirmPassword: " + confirmPassword);
|
||||
System.out.println(!newPassword.equals(confirmPassword));
|
||||
if (!newPassword.equals(confirmPassword)) {
|
||||
System.out.println("ici");
|
||||
response.sendRedirect(request.getContextPath() + "/reset-password?error=1&token=" + recoveryPasswordToken.getToken());
|
||||
return;
|
||||
}
|
||||
user.setPassword(newPassword);
|
||||
DAO_JPA_User daoJpaUser = null;
|
||||
try {
|
||||
daoJpaUser = new DAO_JPA_User();
|
||||
daoJpaUser.update(user);
|
||||
response.sendRedirect(request.getContextPath() + "/login?success=password-modified");
|
||||
} catch (DAOException e) {
|
||||
response.sendRedirect(request.getContextPath() + "/reset-password?error=2");
|
||||
}
|
||||
}
|
||||
|
||||
public static RecoveryPasswordToken findRecoveryToken(String token) {
|
||||
try {
|
||||
DAO_JPA_RecoveryPasswordToken daoJpaRecoveryPasswordToken = new DAO_JPA_RecoveryPasswordToken();
|
||||
RecoveryPasswordToken[] recoveryPasswordTokens = daoJpaRecoveryPasswordToken.findByField("token",token);
|
||||
if (recoveryPasswordTokens.length == 0) {
|
||||
return null;
|
||||
}
|
||||
return recoveryPasswordTokens[0];
|
||||
} catch (DAOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@
|
||||
<class>uppa.project.pojo.User</class>
|
||||
<class>uppa.project.pojo.Game</class>
|
||||
<class>uppa.project.pojo.Player</class>
|
||||
<class>uppa.project.pojo.RecoveryPasswordToken</class>
|
||||
|
||||
<properties>
|
||||
<property name="jakarta.persistence.jdbc.driver" value="com.mysql.cj.jdbc.Driver"/>
|
||||
|
||||
@@ -23,3 +23,10 @@ loginForm.addEventListener("submit", (event) => {
|
||||
.catch(error => console.error("Error:", error))
|
||||
;
|
||||
});
|
||||
|
||||
//Récupération de mot de passe réussie = redirection vers la page de connexion + message d'alerte
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const succes = urlParams.get('succes');
|
||||
if (succes != null) {
|
||||
window.alert(succes);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
const ResetPasswordForm = document.getElementById("resetPasswordForm");
|
||||
|
||||
ResetPasswordForm.addEventListener("submit", function (event) {
|
||||
event.preventDefault();
|
||||
const formData = new FormData(ResetPasswordForm);
|
||||
const data = {};
|
||||
formData.forEach((value, key) => data[key] = value);
|
||||
|
||||
const action = loginForm.getAttribute("action")
|
||||
const method = loginForm.getAttribute("method")
|
||||
|
||||
|
||||
fetch("/reset-password", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
body: JSON.stringify(data)
|
||||
}).then(response => {
|
||||
if (response.ok) {
|
||||
window.location.href = "/login";
|
||||
} else {
|
||||
response.json().then(data => {
|
||||
alert(data.message);
|
||||
});
|
||||
}
|
||||
}).catch(error => {
|
||||
console.error("Error:", error);
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
<%@ page import="uppa.project.dao.jpa.DAO_JPA_RecoveryPasswordToken" %>
|
||||
<%@ page import="uppa.project.pojo.RecoveryPasswordToken" %>
|
||||
<%@ page import="uppa.project.dao.DAOException" %>
|
||||
<%--
|
||||
Created by IntelliJ IDEA.
|
||||
User: kmitr
|
||||
Date: 22/03/2024
|
||||
Time: 13:48
|
||||
To change this template use File | Settings | File Templates.
|
||||
--%>
|
||||
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
|
||||
<html>
|
||||
<head>
|
||||
<title>Recovery password</title>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<%
|
||||
DAO_JPA_RecoveryPasswordToken dao = null;
|
||||
RecoveryPasswordToken[] token;
|
||||
try {
|
||||
dao = new DAO_JPA_RecoveryPasswordToken();
|
||||
token = dao.findByField("token",request.getParameter("token"));
|
||||
} catch (DAOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
if (token.length == 0 || token[0] == null || token[0].getExpirationDate()== null) {%>
|
||||
<p> Lien invalide </p>
|
||||
<%
|
||||
} else if (token[0].getExpirationDate().compareTo(new java.util.Date()) >0){
|
||||
%>
|
||||
<p> Lien expiré </p>
|
||||
<%
|
||||
} else {
|
||||
%>
|
||||
<jsp:include page="../components/navbar.jsp"/>
|
||||
<h1>Récupération du mot de passe</h1>
|
||||
<form id="resetPasswordForm" action="reset-password" method="post">
|
||||
<label for="newPassword">Nouveau mot de passe</label>
|
||||
<input type="password" id="newPassword" name="newPassword" required>
|
||||
<label for="confirmPassword">Confirmer le mot de passe</label>
|
||||
<input type="password" id="confirmPassword" name="confirmPassword" required>
|
||||
<% if (request.getParameter("error") != null && request.getParameter("error").equals("1")) {%>
|
||||
<p>Les mots de passe ne correspondent pas</p>
|
||||
<% } %>
|
||||
<input type="hidden" name="token" value="${param.token}">
|
||||
<input type="submit" value="Valider">
|
||||
</form>
|
||||
<%
|
||||
}
|
||||
%>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user