db: Created "connections" table to store tokens. backend: created "/connect" endpoint.

This commit is contained in:
Yohan Boujon 2024-12-22 10:51:28 +01:00
parent e3ce964ae1
commit 2596c12178
6 changed files with 176 additions and 4 deletions

View file

@ -5,6 +5,14 @@ CREATE TABLE `users` (
`password` text NOT NULL
);
CREATE TABLE `connections` (
`id` integer UNIQUE PRIMARY KEY AUTO_INCREMENT,
`id_user` integer NOT NULL,
`token` varchar(128) UNIQUE NOT NULL,
`created_at` timestamp DEFAULT (now()),
`expires_at` timestamp
);
CREATE TABLE `roles` (
`id` integer UNIQUE PRIMARY KEY AUTO_INCREMENT,
`name` text UNIQUE NOT NULL
@ -30,6 +38,8 @@ CREATE TABLE `feedback` (
`message` text NOT NULL
);
ALTER TABLE `connections` ADD FOREIGN KEY (`id_user`) REFERENCES `users` (`id`);
ALTER TABLE `users` ADD FOREIGN KEY (`id_role`) REFERENCES `roles` (`id`);
ALTER TABLE `requests` ADD FOREIGN KEY (`id_user`) REFERENCES `users` (`id`);

View file

@ -0,0 +1,72 @@
package insa.application.helpapp.rest;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import jakarta.persistence.Column;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import java.time.LocalDateTime;
@Entity
@Table(name = "connections", schema = "service-architecture")
public class Connection {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@Column(name = "id_user", nullable = false)
private int idUser;
@Column(name = "token", nullable = false, unique = true, length = 128)
private String token;
@Column(name = "created_at", nullable = false)
private LocalDateTime createdAt;
@Column(name = "expires_at", nullable = false)
private LocalDateTime expiresAt;
// Getters and Setters
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getidUser() {
return idUser;
}
public void setidUser(int idUser) {
this.idUser = idUser;
}
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
public LocalDateTime getCreatedAt() {
return createdAt;
}
public void setCreatedAt(LocalDateTime createdAt) {
this.createdAt = createdAt;
}
public LocalDateTime getExpiresAt() {
return expiresAt;
}
public void setExpiresAt(LocalDateTime expiresAt) {
this.expiresAt = expiresAt;
}
}

View file

@ -0,0 +1,9 @@
package insa.application.helpapp.rest;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
public interface ConnectionRepository extends JpaRepository<Connection, Integer> {
List<Connection> findByIdUser(int idUser);
}

View file

@ -1,6 +1,19 @@
package insa.application.helpapp.rest;
import org.springframework.data.jpa.repository.JpaRepository;
/*
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
*/
import java.util.List;
public interface UserRepository extends JpaRepository<User, Integer> {
List<User> findByUsername(String username);
/*
@Query("SELECT t FROM ConnectionToken t WHERE t.userId = :userId")
List<ConnectionToken> findCustomTokensByUserId(@Param("userId") int userId);
*/
}

View file

@ -3,17 +3,38 @@ package insa.application.helpapp.rest;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.hibernate.type.descriptor.java.LocalDateTimeJavaType;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.HashMap;
import java.util.Map;
import java.util.List;
import java.time.LocalDateTime;
import java.math.BigInteger;
import java.security.SecureRandom;
import java.util.Base64;
@SpringBootApplication
@RestController
public class UserServiceApplication {
@Autowired
private UserRepository userRepository;
@Autowired
private ConnectionRepository connectionRepository;
// https://stackoverflow.com/users/774398/patrick
public static String generateRandomBase64Token(int byteLength) {
SecureRandom secureRandom = new SecureRandom();
byte[] token = new byte[byteLength-32];
secureRandom.nextBytes(token);
return Base64.getUrlEncoder().withoutPadding().encodeToString(token); //base64 encoding
}
public static void main(String[] args) {
SpringApplication.run(UserServiceApplication.class, args);
@ -34,7 +55,7 @@ public class UserServiceApplication {
// Post should be : /create_user?idRole=1&username=toto&password=1234
@PostMapping("/create_user")
public User createUser(int idRole, String username, String password) {
public User createUser(@RequestParam int idRole, @RequestParam String username, @RequestParam String password) {
User user = new User();
user.setIdRole(idRole);
user.setUsername(username);
@ -43,4 +64,50 @@ public class UserServiceApplication {
return userRepository.save(user);
}
// Post should be : /connect?username=toto&password=1234
// Response can vary: Error if username/password doesn't exist/match
// Response if success: userId (int), expiresAt (time), token (varchar(128))
@PostMapping("/connect")
public ResponseEntity<?> connect(@RequestParam String username, @RequestParam String password)
{
List<User> users = userRepository.findByUsername(username);
// Checks username
if(users.isEmpty()) {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Username not known.");
}
User user = users.getFirst();
// Checks password
if(!user.getPassword().equals(password)) {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Invalid password.");
}
// Checks if token already exists
List<Connection> connections = connectionRepository.findByIdUser(user.getId());
Map<String, Object> response = new HashMap<>();
Connection connection = new Connection();
if(!connections.isEmpty() && (connections.getFirst().getExpiresAt().isBefore(LocalDateTime.now())))
{
// Remove the old token
connectionRepository.delete(connections.getFirst());
// Create new token if password & username is correct
// Get User ID
connection.setidUser(user.getId());
// Generate token
connection.setToken(generateRandomBase64Token(128));
// Creation date and expiration date
connection.setCreatedAt(LocalDateTime.now());
connection.setExpiresAt(LocalDateTime.now().plusDays(1));
// Save created Connection
connectionRepository.save(connection);
} else {
connection = connections.getFirst();
}
// Reponse to client
response.put("token", connection.getToken());
response.put("userId", connection.getidUser());
response.put("expiresAt", connection.getExpiresAt());
return ResponseEntity.ok(response);
}
}

View file

@ -43,12 +43,12 @@ check_services() {
# Function to start services
start_services() {
echo "" > ../process.tmp
echo "" > "$SCRIPT_DIR"/process.tmp
cd "$SCRIPT_DIR/helpapp-backend" || exit 1
for service in "${services[@]}"; do
echo "> Starting $service..."
mvn spring-boot:run -pl "$service" > /dev/null 2>&1 &
echo -e "$!" >> ../process.tmp
echo -e "$!" >> "$SCRIPT_DIR"/process.tmp
done
echo "> Waiting for the services to establish connection..."
check_services
@ -63,6 +63,7 @@ stop_services() {
echo -e "\t> Killing process on port $port..."
fuser -k $port/tcp
done
rm "$SCRIPT_DIR"/process.tmp
}
# Check command line arguments