feat: add jakarta rest todo implementation with devcontainer setup
This commit is contained in:
parent
b75d5b2d11
commit
d605c3bd7d
24 changed files with 1286 additions and 0 deletions
|
|
@ -0,0 +1,8 @@
|
||||||
|
.git
|
||||||
|
.github
|
||||||
|
.settings
|
||||||
|
target
|
||||||
|
*.iml
|
||||||
|
.idea
|
||||||
|
.vscode
|
||||||
|
node_modules
|
||||||
27
cmd/jws/projects/jakarta-rest-todo/.devcontainer/.gitignore
vendored
Normal file
27
cmd/jws/projects/jakarta-rest-todo/.devcontainer/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
# Maven
|
||||||
|
target/
|
||||||
|
!.mvn/wrapper/maven-wrapper.jar
|
||||||
|
!**/src/main/**/target/
|
||||||
|
!**/src/test/**/target/
|
||||||
|
|
||||||
|
# IDE-spezifische Dateien
|
||||||
|
.idea/
|
||||||
|
*.iws
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
.vscode/
|
||||||
|
.settings/
|
||||||
|
.classpath
|
||||||
|
.project
|
||||||
|
.factorypath
|
||||||
|
|
||||||
|
# Temporäre Dateien
|
||||||
|
*.log
|
||||||
|
*.tmp
|
||||||
|
*.temp
|
||||||
|
|
||||||
|
# Lokale Konfigurationsdateien
|
||||||
|
src/main/resources/application-local.properties
|
||||||
|
|
||||||
|
# Devcontainer Volumen
|
||||||
|
.devcontainer/postgres-data/
|
||||||
12
cmd/jws/projects/jakarta-rest-todo/.devcontainer/Dockerfile
Normal file
12
cmd/jws/projects/jakarta-rest-todo/.devcontainer/Dockerfile
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
FROM icr.io/appcafe/open-liberty:23.0.0.4-kernel-slim-java17-openj9-ubi
|
||||||
|
|
||||||
|
COPY --chown=1001:0 src/main/liberty/config /config
|
||||||
|
# # Verzeichnis erstellen und PostgreSQL JDBC-Treiber herunterladen
|
||||||
|
RUN mkdir -p /config/lib && \
|
||||||
|
curl -o /config/lib/postgresql.jar https://jdbc.postgresql.org/download/postgresql-42.6.0.jar
|
||||||
|
|
||||||
|
RUN features.sh
|
||||||
|
|
||||||
|
#COPY --chown=1001:0 target/*.war /config/apps
|
||||||
|
|
||||||
|
RUN configure.sh
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
FROM mcr.microsoft.com/devcontainers/java:1-21-bullseye
|
||||||
|
|
||||||
|
#ARG INSTALL_MAVEN="true"
|
||||||
|
#ARG MAVEN_VERSION=""
|
||||||
|
|
||||||
|
#ARG INSTALL_GRADLE="false"
|
||||||
|
#ARG GRADLE_VERSION=""
|
||||||
|
|
||||||
|
#RUN if [ "${INSTALL_MAVEN}" = "true" ]; then su vscode -c "umask 0002 && . /usr/local/sdkman/bin/sdkman-init.sh && sdk install maven \"${MAVEN_VERSION}\""; fi \
|
||||||
|
# && if [ "${INSTALL_GRADLE}" = "true" ]; then su vscode -c "umask 0002 && . /usr/local/sdkman/bin/sdkman-init.sh && sdk install gradle \"${GRADLE_VERSION}\""; fi
|
||||||
|
|
||||||
|
# Hier kannst du zusätzliche Tools oder Bibliotheken installieren, die du für die Entwicklung benötigst.
|
||||||
|
# Zum Beispiel den PostgreSQL JDBC-Treiber, wenn du ihn für die Entwicklung benötigst:
|
||||||
|
RUN apt-get update && apt-get install -y curl && curl -o /tmp/postgresql.jar https://jdbc.postgresql.org/download/postgresql-42.6.0.jar && mkdir -p /usr/local/lib/ && mv /tmp/postgresql.jar /usr/local/lib/postgresql.jar
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
"name": "Java & PostgreSQL",
|
||||||
|
"dockerComposeFile": "docker-compose.yml",
|
||||||
|
"service": "app",
|
||||||
|
"workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",
|
||||||
|
"forwardPorts": [9080, 5432, 9433],
|
||||||
|
"postCreateCommand": "mvn clean install -DskipTests",
|
||||||
|
"remoteUser": "vscode",
|
||||||
|
"features": {
|
||||||
|
"ghcr.io/devcontainers/features/docker-in-docker:2": {"version": "latest"},
|
||||||
|
"ghcr.io/devcontainers-extra/features/maven-sdkman:2": {"version": "latest"},
|
||||||
|
"ghcr.io/devcontainers/features/git:1": {"version": "latest"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
services:
|
||||||
|
app:
|
||||||
|
container_name: javadev
|
||||||
|
build:
|
||||||
|
context: ../
|
||||||
|
dockerfile: .devcontainer/Dockerfile.dev
|
||||||
|
volumes:
|
||||||
|
- ../..:/workspaces:cached
|
||||||
|
- ./app:/app
|
||||||
|
environment:
|
||||||
|
POSTGRES_HOST: postgresdb
|
||||||
|
POSTGRES_PORT: 5432
|
||||||
|
POSTGRES_DB: postgres
|
||||||
|
POSTGRES_USER: postgres
|
||||||
|
POSTGRES_PASSWORD: postgres
|
||||||
|
networks:
|
||||||
|
- my_network
|
||||||
|
command: sleep infinity
|
||||||
|
|
||||||
|
openliberty:
|
||||||
|
container_name: openliberty_app
|
||||||
|
build:
|
||||||
|
context: ../
|
||||||
|
dockerfile: .devcontainer/Dockerfile
|
||||||
|
ports:
|
||||||
|
- "9080:9080"
|
||||||
|
- "9443:9443"
|
||||||
|
environment:
|
||||||
|
POSTGRES_HOST: postgresdb
|
||||||
|
POSTGRES_PORT: 5432
|
||||||
|
POSTGRES_DB: todo_db
|
||||||
|
POSTGRES_USER: postgres
|
||||||
|
POSTGRES_PASSWORD: postgres
|
||||||
|
volumes:
|
||||||
|
- ./app:/config/dropins
|
||||||
|
depends_on:
|
||||||
|
- db
|
||||||
|
networks:
|
||||||
|
- my_network
|
||||||
|
|
||||||
|
db:
|
||||||
|
container_name: postgresdb
|
||||||
|
image: postgres:latest
|
||||||
|
restart: unless-stopped
|
||||||
|
volumes:
|
||||||
|
- postgres-data:/var/lib/postgresql/data
|
||||||
|
- ./init.sql:/docker-entrypoint-initdb.d/init.sql
|
||||||
|
environment:
|
||||||
|
POSTGRES_PASSWORD: postgres
|
||||||
|
POSTGRES_USER: postgres
|
||||||
|
POSTGRES_DB: todo_db
|
||||||
|
networks:
|
||||||
|
- my_network
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
postgres-data:
|
||||||
|
|
||||||
|
networks:
|
||||||
|
my_network:
|
||||||
|
driver: bridge
|
||||||
19
cmd/jws/projects/jakarta-rest-todo/.devcontainer/init.sql
Normal file
19
cmd/jws/projects/jakarta-rest-todo/.devcontainer/init.sql
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
CREATE TABLE users (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
username VARCHAR(255) NOT NULL UNIQUE,
|
||||||
|
password VARCHAR(255) NOT NULL,
|
||||||
|
email VARCHAR(255) NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE todos (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
title VARCHAR(255) NOT NULL,
|
||||||
|
description VARCHAR(1000),
|
||||||
|
target_date DATE,
|
||||||
|
completed BOOLEAN,
|
||||||
|
user_id BIGINT NOT NULL,
|
||||||
|
FOREIGN KEY (user_id) REFERENCES users(id)
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO users (username, password, email) VALUES
|
||||||
|
('test', '$2a$12$nt7xQKNDKZhxQFZGD5Wy0.Uh0wdPtWDgwfnWnPLgBWnQDGGkNLKBi', 'test@example.com');
|
||||||
|
|
@ -0,0 +1,112 @@
|
||||||
|
<?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.todoapp</groupId>
|
||||||
|
<artifactId>todo-app</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
<packaging>war</packaging>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
<maven.compiler.source>17</maven.compiler.source>
|
||||||
|
<maven.compiler.target>17</maven.compiler.target>
|
||||||
|
<jakartaee.version>10.0.0</jakartaee.version>
|
||||||
|
<hibernate.version>6.2.5.Final</hibernate.version>
|
||||||
|
<postgresql.version>42.6.0</postgresql.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<!-- Jakarta EE 10 API -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>jakarta.platform</groupId>
|
||||||
|
<artifactId>jakarta.jakartaee-api</artifactId>
|
||||||
|
<version>${jakartaee.version}</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Hibernate Core -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.hibernate.orm</groupId>
|
||||||
|
<artifactId>hibernate-core</artifactId>
|
||||||
|
<version>${hibernate.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- PostgreSQL JDBC Driver -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.postgresql</groupId>
|
||||||
|
<artifactId>postgresql</artifactId>
|
||||||
|
<version>${postgresql.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- JSTL -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>jakarta.servlet.jsp.jstl</groupId>
|
||||||
|
<artifactId>jakarta.servlet.jsp.jstl-api</artifactId>
|
||||||
|
<version>3.0.0</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.glassfish.web</groupId>
|
||||||
|
<artifactId>jakarta.servlet.jsp.jstl</artifactId>
|
||||||
|
<version>3.0.1</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- JAX-RS -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>jakarta.ws.rs</groupId>
|
||||||
|
<artifactId>jakarta.ws.rs-api</artifactId>
|
||||||
|
<version>3.1.0</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- JSON-Binding -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>jakarta.json.bind</groupId>
|
||||||
|
<artifactId>jakarta.json.bind-api</artifactId>
|
||||||
|
<version>3.0.0</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- JSON-Processing -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>jakarta.json</groupId>
|
||||||
|
<artifactId>jakarta.json-api</artifactId>
|
||||||
|
<version>2.1.0</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.hibernate</groupId>
|
||||||
|
<artifactId>hibernate-core</artifactId>
|
||||||
|
<version>6.3.1.Final</version> <!-- Stelle sicher, dass du eine aktuelle Version benutzt -->
|
||||||
|
</dependency>
|
||||||
|
<!-- Mindestens zum Passwort-Hashing -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>at.favre.lib</groupId>
|
||||||
|
<artifactId>bcrypt</artifactId>
|
||||||
|
<version>0.10.2</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<finalName>todo-app</finalName>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>3.10.1</version>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-war-plugin</artifactId>
|
||||||
|
<version>3.3.2</version>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>io.openliberty.tools</groupId>
|
||||||
|
<artifactId>liberty-maven-plugin</artifactId>
|
||||||
|
<version>3.7.1</version>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
||||||
|
|
@ -0,0 +1,135 @@
|
||||||
|
package com.todoapp.dao;
|
||||||
|
|
||||||
|
import com.todoapp.model.Todo;
|
||||||
|
import com.todoapp.model.User;
|
||||||
|
import jakarta.enterprise.context.ApplicationScoped;
|
||||||
|
import jakarta.inject.Inject;
|
||||||
|
import org.hibernate.Session;
|
||||||
|
import org.hibernate.SessionFactory;
|
||||||
|
import org.hibernate.Transaction;
|
||||||
|
import org.hibernate.query.Query;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@ApplicationScoped
|
||||||
|
public class TodoDAO {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private SessionFactory sessionFactory;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private UserDAO userDAO;
|
||||||
|
|
||||||
|
public Todo saveTodo(Todo todo, String username) {
|
||||||
|
Transaction transaction = null;
|
||||||
|
try (Session session = sessionFactory.openSession()) {
|
||||||
|
transaction = session.beginTransaction();
|
||||||
|
|
||||||
|
// Benutzer aus der Datenbank holen
|
||||||
|
User user = userDAO.getUserByUsername(username);
|
||||||
|
if (user == null) {
|
||||||
|
throw new IllegalArgumentException("User not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
todo.setUser(user);
|
||||||
|
session.persist(todo);
|
||||||
|
transaction.commit();
|
||||||
|
return todo;
|
||||||
|
} catch (Exception e) {
|
||||||
|
if (transaction != null) {
|
||||||
|
transaction.rollback();
|
||||||
|
}
|
||||||
|
e.printStackTrace();
|
||||||
|
throw new RuntimeException("Error saving todo", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Todo updateTodo(Todo todo) {
|
||||||
|
Transaction transaction = null;
|
||||||
|
try (Session session = sessionFactory.openSession()) {
|
||||||
|
transaction = session.beginTransaction();
|
||||||
|
Todo updatedTodo = session.merge(todo);
|
||||||
|
transaction.commit();
|
||||||
|
return updatedTodo;
|
||||||
|
} catch (Exception e) {
|
||||||
|
if (transaction != null) {
|
||||||
|
transaction.rollback();
|
||||||
|
}
|
||||||
|
e.printStackTrace();
|
||||||
|
throw new RuntimeException("Error updating todo", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean deleteTodo(Long id) {
|
||||||
|
Transaction transaction = null;
|
||||||
|
try (Session session = sessionFactory.openSession()) {
|
||||||
|
transaction = session.beginTransaction();
|
||||||
|
Todo todo = session.get(Todo.class, id);
|
||||||
|
if (todo != null) {
|
||||||
|
session.remove(todo);
|
||||||
|
transaction.commit();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} catch (Exception e) {
|
||||||
|
if (transaction != null) {
|
||||||
|
transaction.rollback();
|
||||||
|
}
|
||||||
|
e.printStackTrace();
|
||||||
|
throw new RuntimeException("Error deleting todo", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Todo getTodoById(Long id) {
|
||||||
|
try (Session session = sessionFactory.openSession()) {
|
||||||
|
return session.get(Todo.class, id);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
throw new RuntimeException("Error getting todo by ID", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Todo> getAllTodos() {
|
||||||
|
try (Session session = sessionFactory.openSession()) {
|
||||||
|
return session.createQuery("FROM Todo", Todo.class).list();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
throw new RuntimeException("Error getting all todos", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Todo> getTodosByUsername(String username) {
|
||||||
|
try (Session session = sessionFactory.openSession()) {
|
||||||
|
Query<Todo> query = session.createQuery(
|
||||||
|
"FROM Todo t WHERE t.user.username = :username ORDER BY t.completed, t.targetDate", Todo.class);
|
||||||
|
query.setParameter("username", username);
|
||||||
|
return query.list();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
throw new RuntimeException("Error getting todos by username", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Todo> getCompletedTodosByUsername(String username) {
|
||||||
|
try (Session session = sessionFactory.openSession()) {
|
||||||
|
Query<Todo> query = session.createQuery(
|
||||||
|
"FROM Todo t WHERE t.user.username = :username AND t.completed = true", Todo.class);
|
||||||
|
query.setParameter("username", username);
|
||||||
|
return query.list();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
throw new RuntimeException("Error getting completed todos", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Todo> getIncompleteTodosByUsername(String username) {
|
||||||
|
try (Session session = sessionFactory.openSession()) {
|
||||||
|
Query<Todo> query = session.createQuery(
|
||||||
|
"FROM Todo t WHERE t.user.username = :username AND t.completed = false ORDER BY t.targetDate", Todo.class);
|
||||||
|
query.setParameter("username", username);
|
||||||
|
return query.list();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
throw new RuntimeException("Error getting incomplete todos", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,124 @@
|
||||||
|
package com.todoapp.dao;
|
||||||
|
|
||||||
|
import com.todoapp.model.User;
|
||||||
|
import com.todoapp.util.HibernateUtil;
|
||||||
|
import jakarta.enterprise.context.ApplicationScoped;
|
||||||
|
import jakarta.inject.Inject;
|
||||||
|
import org.hibernate.Session;
|
||||||
|
import org.hibernate.SessionFactory;
|
||||||
|
import org.hibernate.Transaction;
|
||||||
|
import org.hibernate.query.Query;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@ApplicationScoped
|
||||||
|
public class UserDAO {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private SessionFactory sessionFactory;
|
||||||
|
|
||||||
|
public User saveUser(User user) {
|
||||||
|
Transaction transaction = null;
|
||||||
|
try (Session session = sessionFactory.openSession()) {
|
||||||
|
transaction = session.beginTransaction();
|
||||||
|
session.persist(user);
|
||||||
|
transaction.commit();
|
||||||
|
return user;
|
||||||
|
} catch (Exception e) {
|
||||||
|
if (transaction != null) {
|
||||||
|
transaction.rollback();
|
||||||
|
}
|
||||||
|
e.printStackTrace();
|
||||||
|
throw new RuntimeException("Error saving user", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public User updateUser(User user) {
|
||||||
|
Transaction transaction = null;
|
||||||
|
try (Session session = sessionFactory.openSession()) {
|
||||||
|
transaction = session.beginTransaction();
|
||||||
|
User updatedUser = session.merge(user);
|
||||||
|
transaction.commit();
|
||||||
|
return updatedUser;
|
||||||
|
} catch (Exception e) {
|
||||||
|
if (transaction != null) {
|
||||||
|
transaction.rollback();
|
||||||
|
}
|
||||||
|
e.printStackTrace();
|
||||||
|
throw new RuntimeException("Error updating user", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean deleteUser(Long id) {
|
||||||
|
Transaction transaction = null;
|
||||||
|
try (Session session = sessionFactory.openSession()) {
|
||||||
|
transaction = session.beginTransaction();
|
||||||
|
User user = session.get(User.class, id);
|
||||||
|
if (user != null) {
|
||||||
|
session.remove(user);
|
||||||
|
transaction.commit();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} catch (Exception e) {
|
||||||
|
if (transaction != null) {
|
||||||
|
transaction.rollback();
|
||||||
|
}
|
||||||
|
e.printStackTrace();
|
||||||
|
throw new RuntimeException("Error deleting user", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public User getUserById(Long id) {
|
||||||
|
try (Session session = sessionFactory.openSession()) {
|
||||||
|
return session.get(User.class, id);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
throw new RuntimeException("Error getting user by ID", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public User getUserByUsername(String username) {
|
||||||
|
try (Session session = sessionFactory.openSession()) {
|
||||||
|
Query<User> query = session.createQuery("FROM User WHERE username = :username", User.class);
|
||||||
|
query.setParameter("username", username);
|
||||||
|
return query.uniqueResult();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
throw new RuntimeException("Error getting user by username", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<User> getAllUsers() {
|
||||||
|
try (Session session = sessionFactory.openSession()) {
|
||||||
|
return session.createQuery("FROM User", User.class).list();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
throw new RuntimeException("Error getting all users", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean usernameExists(String username) {
|
||||||
|
try (Session session = sessionFactory.openSession()) {
|
||||||
|
Query<Long> query = session.createQuery(
|
||||||
|
"SELECT COUNT(u) FROM User u WHERE u.username = :username", Long.class);
|
||||||
|
query.setParameter("username", username);
|
||||||
|
return query.uniqueResult() > 0;
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
throw new RuntimeException("Error checking if username exists", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean emailExists(String email) {
|
||||||
|
try (Session session = sessionFactory.openSession()) {
|
||||||
|
Query<Long> query = session.createQuery(
|
||||||
|
"SELECT COUNT(u) FROM User u WHERE u.email = :email", Long.class);
|
||||||
|
query.setParameter("email", email);
|
||||||
|
return query.uniqueResult() > 0;
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
throw new RuntimeException("Error checking if email exists", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
package com.todoapp.dto;
|
||||||
|
|
||||||
|
public class LoginRequest {
|
||||||
|
private String username;
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
// Getter und Setter
|
||||||
|
public String getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUsername(String username) {
|
||||||
|
this.username = username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPassword() {
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPassword(String password) {
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
package com.todoapp.dto;
|
||||||
|
|
||||||
|
public class RegistrationRequest {
|
||||||
|
private String username;
|
||||||
|
private String password;
|
||||||
|
private String email;
|
||||||
|
|
||||||
|
// Getter und Setter
|
||||||
|
public String getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUsername(String username) {
|
||||||
|
this.username = username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPassword() {
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPassword(String password) {
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEmail() {
|
||||||
|
return email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEmail(String email) {
|
||||||
|
this.email = email;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,109 @@
|
||||||
|
package com.todoapp.model;
|
||||||
|
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import jakarta.json.bind.annotation.JsonbTransient;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "todos")
|
||||||
|
public class Todo implements Serializable {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Column(nullable = false)
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
@Column(length = 1000)
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
@Column(name = "target_date")
|
||||||
|
@Temporal(TemporalType.DATE)
|
||||||
|
private Date targetDate;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
private boolean completed;
|
||||||
|
|
||||||
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
|
@JoinColumn(name = "user_id", nullable = false)
|
||||||
|
@JsonbTransient // Verhindert zirkuläre Referenzen
|
||||||
|
private User user;
|
||||||
|
|
||||||
|
// Konstruktoren
|
||||||
|
public Todo() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Todo(String title, String description, Date targetDate, boolean completed) {
|
||||||
|
this.title = title;
|
||||||
|
this.description = description;
|
||||||
|
this.targetDate = targetDate;
|
||||||
|
this.completed = completed;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Getter und Setter
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTitle() {
|
||||||
|
return title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTitle(String title) {
|
||||||
|
this.title = title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDescription(String description) {
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getTargetDate() {
|
||||||
|
return targetDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTargetDate(Date targetDate) {
|
||||||
|
this.targetDate = targetDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isCompleted() {
|
||||||
|
return completed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCompleted(boolean completed) {
|
||||||
|
this.completed = completed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public User getUser() {
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUser(User user) {
|
||||||
|
this.user = user;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Zusätzliche Methode für REST-Antworten
|
||||||
|
public Long getUserId() {
|
||||||
|
return user != null ? user.getId() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Todo{" +
|
||||||
|
"id=" + id +
|
||||||
|
", title='" + title + '\'' +
|
||||||
|
", description='" + description + '\'' +
|
||||||
|
", targetDate=" + targetDate +
|
||||||
|
", completed=" + completed +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,101 @@
|
||||||
|
package com.todoapp.model;
|
||||||
|
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import jakarta.json.bind.annotation.JsonbTransient;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "users")
|
||||||
|
public class User implements Serializable {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Column(nullable = false, unique = true)
|
||||||
|
private String username;
|
||||||
|
|
||||||
|
@Column(nullable = false)
|
||||||
|
@JsonbTransient // Verhindert, dass das Passwort in JSON serialisiert wird
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
@Column(nullable = false)
|
||||||
|
private String email;
|
||||||
|
|
||||||
|
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
|
||||||
|
@JsonbTransient // Verhindert zirkuläre Referenzen bei der JSON-Serialisierung
|
||||||
|
private List<Todo> todos = new ArrayList<>();
|
||||||
|
|
||||||
|
// Konstruktoren
|
||||||
|
public User() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public User(String username, String password, String email) {
|
||||||
|
this.username = username;
|
||||||
|
this.password = password;
|
||||||
|
this.email = email;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Getter und Setter
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUsername(String username) {
|
||||||
|
this.username = username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPassword() {
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPassword(String password) {
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEmail() {
|
||||||
|
return email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEmail(String email) {
|
||||||
|
this.email = email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Todo> getTodos() {
|
||||||
|
return todos;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTodos(List<Todo> todos) {
|
||||||
|
this.todos = todos;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hilfsmethoden
|
||||||
|
public void addTodo(Todo todo) {
|
||||||
|
todos.add(todo);
|
||||||
|
todo.setUser(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeTodo(Todo todo) {
|
||||||
|
todos.remove(todo);
|
||||||
|
todo.setUser(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "User{" +
|
||||||
|
"id=" + id +
|
||||||
|
", username='" + username + '\'' +
|
||||||
|
", email='" + email + '\'' +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,95 @@
|
||||||
|
package com.todoapp.rest;
|
||||||
|
|
||||||
|
import com.todoapp.dao.UserDAO;
|
||||||
|
import com.todoapp.model.User;
|
||||||
|
import com.todoapp.dto.LoginRequest;
|
||||||
|
import com.todoapp.dto.RegistrationRequest;
|
||||||
|
|
||||||
|
import jakarta.annotation.security.RolesAllowed;
|
||||||
|
import jakarta.inject.Inject;
|
||||||
|
import jakarta.ws.rs.*;
|
||||||
|
import jakarta.ws.rs.core.MediaType;
|
||||||
|
import jakarta.ws.rs.core.Response;
|
||||||
|
import at.favre.lib.crypto.bcrypt.BCrypt;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Path("/auth")
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
|
public class AuthResource {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private UserDAO userDAO;
|
||||||
|
|
||||||
|
@POST
|
||||||
|
@Path("/register")
|
||||||
|
public Response register(RegistrationRequest request) {
|
||||||
|
if (request.getUsername() == null || request.getPassword() == null || request.getEmail() == null) {
|
||||||
|
return Response.status(Response.Status.BAD_REQUEST)
|
||||||
|
.entity(Map.of("error", "Username, password, and email are required"))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userDAO.usernameExists(request.getUsername())) {
|
||||||
|
System.out.println(userDAO.usernameExists(request.getUsername()));
|
||||||
|
return Response.status(Response.Status.CONFLICT)
|
||||||
|
.entity(Map.of("error", "Username already exists"))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userDAO.emailExists(request.getEmail())) {
|
||||||
|
return Response.status(Response.Status.CONFLICT)
|
||||||
|
.entity(Map.of("error", "Email already exists"))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
User user = new User();
|
||||||
|
user.setUsername(request.getUsername());
|
||||||
|
user.setEmail(request.getEmail());
|
||||||
|
|
||||||
|
String hashedPassword = BCrypt.withDefaults()
|
||||||
|
.hashToString(12, request.getPassword().toCharArray());
|
||||||
|
user.setPassword(hashedPassword);
|
||||||
|
|
||||||
|
userDAO.saveUser(user);
|
||||||
|
|
||||||
|
return Response.status(Response.Status.CREATED)
|
||||||
|
.entity(Map.of("message", "User registered successfully"))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@POST
|
||||||
|
@RolesAllowed("user")
|
||||||
|
@Path("/login")
|
||||||
|
public Response login(LoginRequest request) {
|
||||||
|
// Validierung
|
||||||
|
if (request.getUsername() == null || request.getPassword() == null) {
|
||||||
|
return Response.status(Response.Status.BAD_REQUEST)
|
||||||
|
.entity(Map.of("error", "Username and password are required"))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Benutzer suchen
|
||||||
|
User user = userDAO.getUserByUsername(request.getUsername());
|
||||||
|
if (user == null) {
|
||||||
|
return Response.status(Response.Status.UNAUTHORIZED)
|
||||||
|
.entity(Map.of("error", "Invalid credentials"))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Passwort überprüfen
|
||||||
|
BCrypt.Result result = BCrypt.verifyer()
|
||||||
|
.verify(request.getPassword().toCharArray(), user.getPassword());
|
||||||
|
if (!result.verified) {
|
||||||
|
return Response.status(Response.Status.UNAUTHORIZED)
|
||||||
|
.entity(Map.of("error", "Invalid credentials"))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Erfolgreiche Anmeldung
|
||||||
|
return Response.ok(Map.of(
|
||||||
|
"message", "Login successful",
|
||||||
|
"username", user.getUsername(),
|
||||||
|
"email", user.getEmail())).build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
package com.todoapp.rest;
|
||||||
|
|
||||||
|
import jakarta.ws.rs.ApplicationPath;
|
||||||
|
import jakarta.ws.rs.core.Application;
|
||||||
|
|
||||||
|
@ApplicationPath("/api")
|
||||||
|
public class TodoApplication extends Application {
|
||||||
|
// Die leere Klasse ist ausreichend, um den REST-Endpunkt zu definieren
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,130 @@
|
||||||
|
package com.todoapp.rest;
|
||||||
|
|
||||||
|
import com.todoapp.dao.TodoDAO;
|
||||||
|
import com.todoapp.model.Todo;
|
||||||
|
import jakarta.inject.Inject;
|
||||||
|
import jakarta.ws.rs.*;
|
||||||
|
import jakarta.ws.rs.core.Context;
|
||||||
|
import jakarta.ws.rs.core.MediaType;
|
||||||
|
import jakarta.ws.rs.core.Response;
|
||||||
|
import jakarta.ws.rs.core.SecurityContext;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Path("/todos")
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
|
public class TodoResource {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private TodoDAO todoDAO;
|
||||||
|
|
||||||
|
@GET
|
||||||
|
public Response getAllTodos(@Context SecurityContext securityContext) {
|
||||||
|
String username = securityContext.getUserPrincipal().getName();
|
||||||
|
List<Todo> todos = todoDAO.getTodosByUsername(username);
|
||||||
|
return Response.ok(todos).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Path("/{id}")
|
||||||
|
public Response getTodoById(@PathParam("id") Long id, @Context SecurityContext securityContext) {
|
||||||
|
String username = securityContext.getUserPrincipal().getName();
|
||||||
|
Todo todo = todoDAO.getTodoById(id);
|
||||||
|
|
||||||
|
if (todo == null) {
|
||||||
|
return Response.status(Response.Status.NOT_FOUND).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sicherheitscheck: Nutzer darf nur eigene Todos sehen
|
||||||
|
if (!todo.getUser().getUsername().equals(username)) {
|
||||||
|
return Response.status(Response.Status.FORBIDDEN).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Response.ok(todo).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Path("/completed")
|
||||||
|
public Response getCompletedTodos(@Context SecurityContext securityContext) {
|
||||||
|
String username = securityContext.getUserPrincipal().getName();
|
||||||
|
List<Todo> todos = todoDAO.getCompletedTodosByUsername(username);
|
||||||
|
return Response.ok(todos).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Path("/incomplete")
|
||||||
|
public Response getIncompleteTodos(@Context SecurityContext securityContext) {
|
||||||
|
String username = securityContext.getUserPrincipal().getName();
|
||||||
|
List<Todo> todos = todoDAO.getIncompleteTodosByUsername(username);
|
||||||
|
return Response.ok(todos).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@POST
|
||||||
|
public Response createTodo(Todo todo, @Context SecurityContext securityContext) {
|
||||||
|
String username = securityContext.getUserPrincipal().getName();
|
||||||
|
todo = todoDAO.saveTodo(todo, username);
|
||||||
|
return Response.status(Response.Status.CREATED).entity(todo).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@PUT
|
||||||
|
@Path("/{id}")
|
||||||
|
public Response updateTodo(@PathParam("id") Long id, Todo updatedTodo, @Context SecurityContext securityContext) {
|
||||||
|
String username = securityContext.getUserPrincipal().getName();
|
||||||
|
Todo existingTodo = todoDAO.getTodoById(id);
|
||||||
|
|
||||||
|
if (existingTodo == null) {
|
||||||
|
return Response.status(Response.Status.NOT_FOUND).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sicherheitscheck: Nutzer darf nur eigene Todos aktualisieren
|
||||||
|
if (!existingTodo.getUser().getUsername().equals(username)) {
|
||||||
|
return Response.status(Response.Status.FORBIDDEN).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ID und Benutzer beibehalten
|
||||||
|
updatedTodo.setId(id);
|
||||||
|
updatedTodo.setUser(existingTodo.getUser());
|
||||||
|
|
||||||
|
todoDAO.updateTodo(updatedTodo);
|
||||||
|
return Response.ok(updatedTodo).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@DELETE
|
||||||
|
@Path("/{id}")
|
||||||
|
public Response deleteTodo(@PathParam("id") Long id, @Context SecurityContext securityContext) {
|
||||||
|
String username = securityContext.getUserPrincipal().getName();
|
||||||
|
Todo todo = todoDAO.getTodoById(id);
|
||||||
|
|
||||||
|
if (todo == null) {
|
||||||
|
return Response.status(Response.Status.NOT_FOUND).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sicherheitscheck: Nutzer darf nur eigene Todos löschen
|
||||||
|
if (!todo.getUser().getUsername().equals(username)) {
|
||||||
|
return Response.status(Response.Status.FORBIDDEN).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean deleted = todoDAO.deleteTodo(id);
|
||||||
|
return deleted ? Response.noContent().build() : Response.status(Response.Status.NOT_FOUND).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@PUT
|
||||||
|
@Path("/{id}/complete")
|
||||||
|
public Response markTodoComplete(@PathParam("id") Long id, @Context SecurityContext securityContext) {
|
||||||
|
String username = securityContext.getUserPrincipal().getName();
|
||||||
|
Todo todo = todoDAO.getTodoById(id);
|
||||||
|
|
||||||
|
if (todo == null) {
|
||||||
|
return Response.status(Response.Status.NOT_FOUND).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sicherheitscheck: Nutzer darf nur eigene Todos aktualisieren
|
||||||
|
if (!todo.getUser().getUsername().equals(username)) {
|
||||||
|
return Response.status(Response.Status.FORBIDDEN).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
todo.setCompleted(true);
|
||||||
|
todoDAO.updateTodo(todo);
|
||||||
|
return Response.ok(todo).build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,104 @@
|
||||||
|
package com.todoapp.security;
|
||||||
|
|
||||||
|
import com.todoapp.dao.UserDAO;
|
||||||
|
import com.todoapp.model.User;
|
||||||
|
import jakarta.annotation.Priority;
|
||||||
|
import jakarta.enterprise.context.ApplicationScoped;
|
||||||
|
import jakarta.inject.Inject;
|
||||||
|
import jakarta.ws.rs.Priorities;
|
||||||
|
import jakarta.ws.rs.container.ContainerRequestContext;
|
||||||
|
import jakarta.ws.rs.container.ContainerRequestFilter;
|
||||||
|
import jakarta.ws.rs.core.HttpHeaders;
|
||||||
|
import jakarta.ws.rs.core.Response;
|
||||||
|
import jakarta.ws.rs.core.SecurityContext;
|
||||||
|
import jakarta.ws.rs.ext.Provider;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.security.Principal;
|
||||||
|
import java.util.Base64;
|
||||||
|
import at.favre.lib.crypto.bcrypt.BCrypt;
|
||||||
|
|
||||||
|
@Provider
|
||||||
|
@Priority(Priorities.AUTHENTICATION)
|
||||||
|
@ApplicationScoped
|
||||||
|
public class BasicAuthenticationFilter implements ContainerRequestFilter {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private UserDAO userDAO;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void filter(ContainerRequestContext requestContext) throws IOException {
|
||||||
|
System.out.println("BasicAuthenticationFilter triggered for path: " + requestContext.getUriInfo().getPath());
|
||||||
|
String path = requestContext.getUriInfo().getPath();
|
||||||
|
if (path.endsWith("auth/register") || path.endsWith("auth/login")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String authHeader = requestContext.getHeaderString(HttpHeaders.AUTHORIZATION);
|
||||||
|
if (authHeader == null || !authHeader.startsWith("Basic ")) {
|
||||||
|
abortWithUnauthorized(requestContext);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String[] credentials = extractCredentials(authHeader);
|
||||||
|
if (credentials.length != 2) {
|
||||||
|
abortWithUnauthorized(requestContext);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String username = credentials[0];
|
||||||
|
String password = credentials[1];
|
||||||
|
|
||||||
|
User user = userDAO.getUserByUsername(username);
|
||||||
|
if (user == null) {
|
||||||
|
abortWithUnauthorized(requestContext);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BCrypt.Result result = BCrypt.verifyer()
|
||||||
|
.verify(password.toCharArray(), user.getPassword());
|
||||||
|
if (!result.verified) {
|
||||||
|
abortWithUnauthorized(requestContext);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final SecurityContext currentSecurityContext = requestContext.getSecurityContext();
|
||||||
|
requestContext.setSecurityContext(new SecurityContext() {
|
||||||
|
@Override
|
||||||
|
public Principal getUserPrincipal() {
|
||||||
|
return () -> username;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isUserInRole(String role) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSecure() {
|
||||||
|
return currentSecurityContext.isSecure();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getAuthenticationScheme() {
|
||||||
|
return "BASIC";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
System.out.println("SecurityContext gesetzt für User: " + username);
|
||||||
|
System.out.println("User in Rolle user: " + requestContext.getSecurityContext().isUserInRole("user"));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private String[] extractCredentials(String authHeader) {
|
||||||
|
String base64Credentials = authHeader.substring("Basic ".length()).trim();
|
||||||
|
byte[] decoded = Base64.getDecoder().decode(base64Credentials);
|
||||||
|
String credentials = new String(decoded);
|
||||||
|
return credentials.split(":", 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void abortWithUnauthorized(ContainerRequestContext requestContext) {
|
||||||
|
requestContext.abortWith(Response
|
||||||
|
.status(Response.Status.UNAUTHORIZED)
|
||||||
|
.header(HttpHeaders.WWW_AUTHENTICATE, "Basic realm=\"TodoApp\"")
|
||||||
|
.build());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
package com.todoapp.security;
|
||||||
|
|
||||||
|
import jakarta.ws.rs.container.ContainerRequestContext;
|
||||||
|
import jakarta.ws.rs.container.ContainerResponseContext;
|
||||||
|
import jakarta.ws.rs.container.ContainerResponseFilter;
|
||||||
|
import jakarta.ws.rs.ext.Provider;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
@Provider
|
||||||
|
public class CORSFilter implements ContainerResponseFilter {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext)
|
||||||
|
throws IOException {
|
||||||
|
responseContext.getHeaders().add("Access-Control-Allow-Origin", "*");
|
||||||
|
responseContext.getHeaders().add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
|
||||||
|
responseContext.getHeaders().add("Access-Control-Allow-Headers", "Content-Type, Authorization");
|
||||||
|
responseContext.getHeaders().add("Access-Control-Max-Age", "86400");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
package com.todoapp.util;
|
||||||
|
|
||||||
|
import jakarta.enterprise.context.ApplicationScoped;
|
||||||
|
import jakarta.enterprise.inject.Produces;
|
||||||
|
import org.hibernate.SessionFactory;
|
||||||
|
import org.hibernate.cfg.Configuration;
|
||||||
|
|
||||||
|
@ApplicationScoped
|
||||||
|
public class HibernateUtil {
|
||||||
|
|
||||||
|
private static SessionFactory sessionFactory;
|
||||||
|
|
||||||
|
@Produces
|
||||||
|
@ApplicationScoped
|
||||||
|
public SessionFactory getSessionFactory() {
|
||||||
|
if (sessionFactory == null) {
|
||||||
|
try {
|
||||||
|
Configuration configuration = new Configuration();
|
||||||
|
configuration.setProperty("hibernate.connection.driver_class", "org.postgresql.Driver");
|
||||||
|
configuration.setProperty("hibernate.connection.url", "jdbc:postgresql://postgresdb:5432/todo_db");
|
||||||
|
configuration.setProperty("hibernate.connection.username", "postgres");
|
||||||
|
configuration.setProperty("hibernate.connection.password", "postgres");
|
||||||
|
|
||||||
|
// Entity-Klassen registrieren
|
||||||
|
configuration.addAnnotatedClass(com.todoapp.model.User.class);
|
||||||
|
configuration.addAnnotatedClass(com.todoapp.model.Todo.class);
|
||||||
|
|
||||||
|
sessionFactory = configuration.buildSessionFactory();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sessionFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void shutdown() {
|
||||||
|
if (sessionFactory != null) {
|
||||||
|
sessionFactory.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<server description="OpenLiberty Todo App Server">
|
||||||
|
|
||||||
|
<featureManager>
|
||||||
|
<feature>servlet-6.0</feature>
|
||||||
|
<feature>pages-3.1</feature>
|
||||||
|
<feature>jdbc-4.2</feature>
|
||||||
|
<feature>jndi-1.0</feature>
|
||||||
|
<feature>monitor-1.0</feature>
|
||||||
|
<feature>restfulWS-3.1</feature>
|
||||||
|
<feature>jsonb-3.0</feature>
|
||||||
|
<feature>jsonp-2.1</feature>
|
||||||
|
<!-- <feature>appSecurity-5.0</feature> -->
|
||||||
|
<feature>transportSecurity-1.0</feature>
|
||||||
|
</featureManager>
|
||||||
|
|
||||||
|
<httpEndpoint id="defaultHttpEndpoint"
|
||||||
|
httpPort="9080"
|
||||||
|
httpsPort="9443" />
|
||||||
|
|
||||||
|
<applicationManager autoExpand="true" />
|
||||||
|
|
||||||
|
<dataSource id="PostgresDataSource" jndiName="jdbc/PostgresDataSource">
|
||||||
|
<jdbcDriver libraryRef="PostgresLib" />
|
||||||
|
<properties.postgresql serverName="${POSTGRES_HOST}"
|
||||||
|
portNumber="${POSTGRES_PORT}"
|
||||||
|
databaseName="${POSTGRES_DB}"
|
||||||
|
user="${POSTGRES_USER}"
|
||||||
|
password="${POSTGRES_PASSWORD}" />
|
||||||
|
</dataSource>
|
||||||
|
|
||||||
|
|
||||||
|
<library id="PostgresLib">
|
||||||
|
<fileset dir="${server.config.dir}/lib" includes="postgresql-*.jar" />
|
||||||
|
</library>
|
||||||
|
|
||||||
|
<webApplication location="todo-app.war" contextRoot="/todo-app" />
|
||||||
|
|
||||||
|
</server>
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<persistence xmlns="https://jakarta.ee/xml/ns/persistence"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="https://jakarta.ee/xml/ns/persistence https://jakarta.ee/xml/ns/persistence/persistence_3_0.xsd"
|
||||||
|
version="3.0">
|
||||||
|
<persistence-unit name="todoPU" transaction-type="RESOURCE_LOCAL">
|
||||||
|
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
|
||||||
|
<class>com.todoapp.model.User</class>
|
||||||
|
<class>com.todoapp.model.Todo</class>
|
||||||
|
<properties>
|
||||||
|
<property name="jakarta.persistence.jdbc.driver" value="org.postgresql.Driver"/>
|
||||||
|
<property name="jakarta.persistence.jdbc.url" value="jdbc:postgresql://postgresdb:5432/todo_db"/>
|
||||||
|
<property name="jakarta.persistence.jdbc.user" value="postgres"/>
|
||||||
|
<property name="jakarta.persistence.jdbc.password" value="postgres"/>
|
||||||
|
<property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/>
|
||||||
|
<property name="hibernate.hbm2ddl.auto" value="update"/>
|
||||||
|
<property name="hibernate.show_sql" value="true"/>
|
||||||
|
</properties>
|
||||||
|
</persistence-unit>
|
||||||
|
</persistence>
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE hibernate-configuration PUBLIC
|
||||||
|
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
|
||||||
|
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
|
||||||
|
<hibernate-configuration>
|
||||||
|
<session-factory>
|
||||||
|
<!-- JNDI connection settings -->
|
||||||
|
<property name="hibernate.connection.datasource">jdbc/PostgresDataSource</property>
|
||||||
|
|
||||||
|
<!-- Select our SQL dialect -->
|
||||||
|
<property name="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</property>
|
||||||
|
|
||||||
|
<!-- Echo the SQL to stdout -->
|
||||||
|
<property name="hibernate.show_sql">true</property>
|
||||||
|
|
||||||
|
<!-- Set the current session context -->
|
||||||
|
<property name="hibernate.current_session_context_class">thread</property>
|
||||||
|
|
||||||
|
<!-- Drop and re-create the database schema on startup -->
|
||||||
|
<property name="hibernate.hbm2ddl.auto">update</property>
|
||||||
|
|
||||||
|
<!-- Entity mapping -->
|
||||||
|
<mapping class="com.todoapp.model.User"/>
|
||||||
|
<mapping class="com.todoapp.model.Todo"/>
|
||||||
|
</session-factory>
|
||||||
|
</hibernate-configuration>
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_6_0.xsd"
|
||||||
|
version="6.0">
|
||||||
|
|
||||||
|
<display-name>Todo Application</display-name>
|
||||||
|
|
||||||
|
<session-config>
|
||||||
|
<session-timeout>30</session-timeout>
|
||||||
|
</session-config>
|
||||||
|
</web-app>
|
||||||
Loading…
Add table
Add a link
Reference in a new issue