mirror of
https://github.com/kmitresse/Cards-Rush.git
synced 2026-07-09 21:37:46 +00:00
draft: dev-web - forgotten password token
This commit is contained in:
@@ -43,3 +43,17 @@ CREATE TABLE IF NOT EXISTS player
|
|||||||
FOREIGN KEY (game_id) REFERENCES game (id),
|
FOREIGN KEY (game_id) REFERENCES game (id),
|
||||||
FOREIGN KEY (user_id) REFERENCES `user` (id)
|
FOREIGN KEY (user_id) REFERENCES `user` (id)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS recovery_password_token(
|
||||||
|
id INT NOT NULL AUTO_INCREMENT,
|
||||||
|
email VARCHAR(255) NOT NULL,
|
||||||
|
token VARCHAR(255) NOT NULL,
|
||||||
|
expires_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
PRIMARY KEY (id)
|
||||||
|
);
|
||||||
|
|
||||||
|
DELIMITER //
|
||||||
|
CREATE TRIGGER expires_at BEFORE INSERT ON recovery_password_token FOR EACH ROW
|
||||||
|
BEGIN
|
||||||
|
SET NEW.`expires_at` = TIMESTAMPADD(MINUTE, 15, CURRENT_TIMESTAMP);
|
||||||
|
END;//
|
||||||
|
|||||||
@@ -51,6 +51,11 @@
|
|||||||
<version>${junit.version}</version>
|
<version>${junit.version}</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.sun.mail</groupId>
|
||||||
|
<artifactId>javax.mail</artifactId>
|
||||||
|
<version>1.6.2</version> <!-- Mettez à jour la version si nécessaire -->
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ package uppa.project.dao;
|
|||||||
|
|
||||||
import uppa.project.pojo.Game;
|
import uppa.project.pojo.Game;
|
||||||
import uppa.project.pojo.Player;
|
import uppa.project.pojo.Player;
|
||||||
|
import uppa.project.pojo.RecoveryPasswordToken;
|
||||||
import uppa.project.pojo.User;
|
import uppa.project.pojo.User;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -21,6 +22,7 @@ public abstract class GameDAOFactory {
|
|||||||
protected DAO<User> daoUser = null;
|
protected DAO<User> daoUser = null;
|
||||||
protected DAO<Game> daoGame = null;
|
protected DAO<Game> daoGame = null;
|
||||||
protected DAO<Player> daoPlayer = null;
|
protected DAO<Player> daoPlayer = null;
|
||||||
|
protected DAO<RecoveryPasswordToken> daoRecoveryPasswordToken = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return le DAO pour la classe/table User
|
* @return le DAO pour la classe/table User
|
||||||
@@ -43,4 +45,6 @@ public abstract class GameDAOFactory {
|
|||||||
*/
|
*/
|
||||||
public abstract DAO<Player> getDAOPlayer() throws DAOException;
|
public abstract DAO<Player> getDAOPlayer() throws DAOException;
|
||||||
|
|
||||||
|
public abstract DAO<RecoveryPasswordToken> getDAORecoveryPasswordToken() throws DAOException;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+78
@@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
* DAO_JPA_RecoveryPasswordToken.java, 20/03/2024
|
||||||
|
* UPPA M1 TI 2023-2024
|
||||||
|
* Pas de copyright, aucun droits
|
||||||
|
*/
|
||||||
|
|
||||||
|
package uppa.project.dao.jpa;
|
||||||
|
|
||||||
|
import jakarta.persistence.EntityManager;
|
||||||
|
import jakarta.persistence.TypedQuery;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.List;
|
||||||
|
import uppa.project.dao.DAO;
|
||||||
|
import uppa.project.dao.DAOException;
|
||||||
|
import uppa.project.pojo.RecoveryPasswordToken;
|
||||||
|
import uppa.project.provider.EntityManagerProvider;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DAO pour les utilisateurs
|
||||||
|
*
|
||||||
|
* @author Kévin Mitresse
|
||||||
|
* @author Lucàs Vabre
|
||||||
|
* @see RecoveryPasswordToken
|
||||||
|
* @see DAO
|
||||||
|
*/
|
||||||
|
public class DAO_JPA_RecoveryPasswordToken extends DAO<RecoveryPasswordToken> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gestionnaire d'entités
|
||||||
|
*/
|
||||||
|
private final EntityManager entityManager;
|
||||||
|
|
||||||
|
public DAO_JPA_RecoveryPasswordToken() throws DAOException {
|
||||||
|
this.entityManager = EntityManagerProvider.getInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RecoveryPasswordToken findById(int id) throws DAOException {
|
||||||
|
RecoveryPasswordToken result = entityManager.find(RecoveryPasswordToken.class, new BigDecimal(id));
|
||||||
|
entityManager.flush();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RecoveryPasswordToken[] findByField(String field, String value) throws DAOException {
|
||||||
|
String sqlQuery = String.format("SELECT r FROM RecoveryPasswordToken r WHERE r.%s = (:val)", field);
|
||||||
|
|
||||||
|
TypedQuery<RecoveryPasswordToken> query = entityManager.createQuery(sqlQuery, RecoveryPasswordToken.class);
|
||||||
|
query.setParameter("val", value);
|
||||||
|
List<RecoveryPasswordToken> results = query.getResultList();
|
||||||
|
return results.toArray(new RecoveryPasswordToken[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RecoveryPasswordToken[] findAll() throws DAOException {
|
||||||
|
TypedQuery<RecoveryPasswordToken> query = entityManager.createQuery("SELECT r FROM RecoveryPasswordToken r", RecoveryPasswordToken.class);
|
||||||
|
List<RecoveryPasswordToken> results = query.getResultList();
|
||||||
|
return results.toArray(new RecoveryPasswordToken[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void create(RecoveryPasswordToken data) throws DAOException {
|
||||||
|
update(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update(RecoveryPasswordToken data) throws DAOException {
|
||||||
|
entityManager.getTransaction().begin();
|
||||||
|
entityManager.merge(data);
|
||||||
|
entityManager.getTransaction().commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void delete(RecoveryPasswordToken data) throws DAOException {
|
||||||
|
entityManager.getTransaction().begin();
|
||||||
|
entityManager.remove(data);
|
||||||
|
entityManager.getTransaction().commit();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -36,4 +36,10 @@ public class Game_JPA_DAO_Factory extends GameDAOFactory {
|
|||||||
if (daoPlayer == null) daoPlayer = new DAO_JPA_Player();
|
if (daoPlayer == null) daoPlayer = new DAO_JPA_Player();
|
||||||
return daoPlayer;
|
return daoPlayer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DAO<RecoveryPasswordToken> getDAORecoveryPasswordToken() throws DAOException {
|
||||||
|
if (daoRecoveryPasswordToken == null) daoRecoveryPasswordToken= new DAO_JPA_RecoveryPasswordToken();
|
||||||
|
return daoRecoveryPasswordToken;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,123 @@
|
|||||||
|
package uppa.project.pojo;
|
||||||
|
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.GeneratedValue;
|
||||||
|
import jakarta.persistence.GenerationType;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
import jakarta.persistence.Temporal;
|
||||||
|
import jakarta.persistence.TemporalType;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Représentation d'un token de réinitialisation de mot de passe
|
||||||
|
*
|
||||||
|
* @author Kevin Mitressé
|
||||||
|
* @author Lucàs Vabre
|
||||||
|
*/
|
||||||
|
@Entity
|
||||||
|
@Table(name = "recovery_password_token")
|
||||||
|
public class RecoveryPasswordToken {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@Column(name = "id")
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
private int id;
|
||||||
|
@Column(name = "token")
|
||||||
|
private String token;
|
||||||
|
@Column(name = "email")
|
||||||
|
private String email;
|
||||||
|
|
||||||
|
@Temporal(TemporalType.TIMESTAMP)
|
||||||
|
@Column(name = "expires_at")
|
||||||
|
private Date expiresAt;
|
||||||
|
|
||||||
|
public RecoveryPasswordToken() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructeur
|
||||||
|
* @param token
|
||||||
|
* @param email
|
||||||
|
*/
|
||||||
|
public RecoveryPasswordToken(String token, String email) {
|
||||||
|
this.token = token;
|
||||||
|
this.email = email;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructeur depuis la base de données
|
||||||
|
* @param id
|
||||||
|
* @param token
|
||||||
|
* @param email
|
||||||
|
*/
|
||||||
|
public RecoveryPasswordToken(int id, String token, String email) {
|
||||||
|
this.id = id;
|
||||||
|
this.token = token;
|
||||||
|
this.email = email;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Récupère l'id de l'instance
|
||||||
|
*
|
||||||
|
* @return l'id
|
||||||
|
*/
|
||||||
|
public int getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Récupère le token
|
||||||
|
*
|
||||||
|
* @return le token
|
||||||
|
*/
|
||||||
|
public String getToken() {
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Définit le token
|
||||||
|
*
|
||||||
|
* @param token
|
||||||
|
*/
|
||||||
|
public void setToken(String token) {
|
||||||
|
this.token = token;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Récupère l'email associé au token
|
||||||
|
*
|
||||||
|
* @return l'email associé au token
|
||||||
|
*/
|
||||||
|
public String getEmail() {
|
||||||
|
return email;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Définit l'email associé au token
|
||||||
|
*
|
||||||
|
* @param email
|
||||||
|
*/
|
||||||
|
public void setEmail(String email) {
|
||||||
|
this.email = email;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Récupère la date d'expiration du token
|
||||||
|
*
|
||||||
|
* @return la date d'expiration du token
|
||||||
|
*/
|
||||||
|
public Date getExpiresAt() {
|
||||||
|
return expiresAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Définit la date d'expiration du token
|
||||||
|
*
|
||||||
|
* @param expiresAt
|
||||||
|
*/
|
||||||
|
public void setExpiresAt(Date expiresAt) {
|
||||||
|
this.expiresAt = expiresAt;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,6 +12,17 @@ import jakarta.servlet.http.HttpServlet;
|
|||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.UUID;
|
||||||
|
import javax.mail.Message;
|
||||||
|
import uppa.project.dao.DAO;
|
||||||
|
import uppa.project.dao.DAOException;
|
||||||
|
import uppa.project.dao.jpa.DAO_JPA_User;
|
||||||
|
import uppa.project.dao.jpa.Game_JPA_DAO_Factory;
|
||||||
|
import uppa.project.pojo.RecoveryPasswordToken;
|
||||||
|
import uppa.project.pojo.User;
|
||||||
|
import java.util.Properties;
|
||||||
|
import javax.mail.*;
|
||||||
|
import javax.mail.internet.*;
|
||||||
|
|
||||||
@WebServlet(name = "forgottenPasswordServlet", value = "/forgotten-password")
|
@WebServlet(name = "forgottenPasswordServlet", value = "/forgotten-password")
|
||||||
public class ForgottenPasswordServlet extends HttpServlet {
|
public class ForgottenPasswordServlet extends HttpServlet {
|
||||||
@@ -28,6 +39,98 @@ public class ForgottenPasswordServlet extends HttpServlet {
|
|||||||
request.getRequestDispatcher("/WEB-INF/views/forgotten-password.jsp").forward(request, response);
|
request.getRequestDispatcher("/WEB-INF/views/forgotten-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 {
|
||||||
|
String email = request.getParameter("email");
|
||||||
|
User user = getUserByEmail(email);
|
||||||
|
if (user == null) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
sendRecoveryEmail(email, token);
|
||||||
|
response.sendRedirect(request.getContextPath() + "/forgotten-password?success=200");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Envoi d'un e-mail de réinitialisation de mot de passe
|
||||||
|
*
|
||||||
|
* @param email
|
||||||
|
* @param token
|
||||||
|
*/
|
||||||
|
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");
|
||||||
|
|
||||||
|
Properties props = new Properties();
|
||||||
|
props.put("mail.smtp.auth", "true");
|
||||||
|
props.put("mail.smtp.starttls.enable", "true");
|
||||||
|
props.put("mail.smtp.host", host);
|
||||||
|
props.put("mail.smtp.port", port);
|
||||||
|
|
||||||
|
Session session = Session.getInstance(props, new Authenticator() {
|
||||||
|
@Override
|
||||||
|
protected PasswordAuthentication getPasswordAuthentication() {
|
||||||
|
return new PasswordAuthentication(username, password);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Création du message
|
||||||
|
Message message = new MimeMessage(session);
|
||||||
|
message.setFrom(new InternetAddress(username));
|
||||||
|
message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(email));
|
||||||
|
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" +
|
||||||
|
"Cordialement,\n" +
|
||||||
|
"L'équipe CardRush");
|
||||||
|
// Envoi du message
|
||||||
|
Transport.send(message);
|
||||||
|
|
||||||
|
System.out.println("E-mail envoyé avec succès à : " + email);
|
||||||
|
} catch (MessagingException e) {
|
||||||
|
throw new RuntimeException("Erreur lors de l'envoi de l'e-mail", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static User getUserByEmail(String email){
|
||||||
|
try {
|
||||||
|
DAO_JPA_User daoJpaUser = new DAO_JPA_User();
|
||||||
|
User[] users = daoJpaUser.findByField("email", email);
|
||||||
|
if (users.length == 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return users[0];
|
||||||
|
} catch (DAOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public void destroy() {
|
public void destroy() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
const forgottenPasswordForm = document.getElementById("forgottenPasswordForm");
|
||||||
|
|
||||||
|
forgottenPasswordForm.addEventListener("submit", (event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
//Recuperer les données du formulaire
|
||||||
|
const formData = new FormData(forgottenPasswordForm);
|
||||||
|
const data = {};
|
||||||
|
formData.forEach((value, key) => data[key] = value);
|
||||||
|
//Recuperer l'URL de l'action et la methode
|
||||||
|
const action = forgottenPasswordForm.getAttribute("action");
|
||||||
|
const method = forgottenPasswordForm.getAttribute("method");
|
||||||
|
//Redirection vers le servlet ForgottenPasswordServlet
|
||||||
|
fetch(action, {
|
||||||
|
headers: {"Content-Type": "application/json"},
|
||||||
|
body: JSON.stringify(data),
|
||||||
|
method,
|
||||||
|
})
|
||||||
|
.then(res => res.json())
|
||||||
|
.then(data => {
|
||||||
|
console.log(data);
|
||||||
|
// if (data.status === 200) window.location.href = data.redirect;
|
||||||
|
})
|
||||||
|
.catch(error => console.error("Error:", error))
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
@@ -11,6 +11,19 @@
|
|||||||
<title>Forgotten Password</title>
|
<title>Forgotten Password</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
<main>
|
||||||
|
<h1>Forgotten Password</h1>
|
||||||
|
<p>Entrer votre email pour recevoir un lien de récupération</p>
|
||||||
|
<form id="forgottenPasswordForm" action="forgotten-password" method="post">
|
||||||
|
<label for="email">Email</label>
|
||||||
|
<input type="email" id="email" name="email" required>
|
||||||
|
<button type="submit">Send</button>
|
||||||
|
</form>
|
||||||
|
<%if(request.getParameter("error") != null){%>
|
||||||
|
<p>L'adresse mail insérée est incorrecte</p>
|
||||||
|
<%} else if (request.getParameter("success") != null) {%>
|
||||||
|
<p>Un email vous a été envoyé</p>
|
||||||
|
<%}%>
|
||||||
|
</main>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Reference in New Issue
Block a user