14 standardize and clean api and fix bruno configuration (#25)

* ADD JWT authentication support with token generation and validation

* ADD JWT handling after successful login

* ADD user authentication and standardize user retrieval

* COMBINE token dtos

* ADD JWT authentication filter

* IMPROVE token handling

* STANDARDIZE API endpoints and improve JWT handling

* REMOVE extra logging

* REMOVE redundant job existence checks

* UPDATE Bruno Google token

* REFACTOR some classes

* ADD JWT cookie check

* ADD AuthProvider and CORS configuration; UPDATE API endpoints for consistency

* ADD JWT validation check;

* ADD profile picture to database

* ADD reload after login to update page

* PATCH login issue

* REMOVE unused classes

* ADJUST logging in JwtFilter

* REMOVE unused React component
This commit is contained in:
Dylan De Faoite
2025-08-10 22:41:37 +02:00
committed by GitHub
parent 20f7ec8db4
commit 662966f138
35 changed files with 916 additions and 252 deletions

View File

@@ -1,45 +0,0 @@
package com.ddf.vodsystem.controllers;
import com.ddf.vodsystem.dto.APIResponse;
import com.ddf.vodsystem.exceptions.NotAuthenticated;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
@RestController
@RequestMapping("/api/v1/auth/")
public class AuthController {
@GetMapping("/user")
public ResponseEntity<APIResponse<Map<String, Object>>> user(@AuthenticationPrincipal OAuth2User principal) {
if (principal == null) {
throw new NotAuthenticated("User is not authenticated");
}
if (
principal.getAttribute("email") == null
|| principal.getAttribute("name") == null
|| principal.getAttribute("picture") == null)
{
return ResponseEntity.status(HttpStatus.BAD_REQUEST).
body(new APIResponse<>(
"error",
"Required user attributes are missing",
null
));
}
return ResponseEntity.ok(
new APIResponse<>("success", "User details retrieved successfully", Map.of(
"name", principal.getAttribute("name"),
"email", principal.getAttribute("email"),
"profilePicture", principal.getAttribute("picture"))
)
);
}
}

View File

@@ -8,15 +8,11 @@ import com.ddf.vodsystem.services.ClipService;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@Controller
@RestController
@RequestMapping("/api/v1/clips")
public class ClipController {
private final ClipService clipService;
@@ -25,12 +21,8 @@ public class ClipController {
this.clipService = clipService;
}
@GetMapping("/")
public ResponseEntity<APIResponse<List<ClipDTO>>> getClips(@AuthenticationPrincipal OAuth2User principal) {
if (principal == null) {
throw new NotAuthenticated("User is not authenticated");
}
@GetMapping("")
public ResponseEntity<APIResponse<List<ClipDTO>>> getClips() {
List<Clip> clips = clipService.getClipsByUser();
List<ClipDTO> clipDTOs = clips.stream()
.map(this::convertToDTO)
@@ -42,11 +34,7 @@ public class ClipController {
}
@GetMapping("/{id}")
public ResponseEntity<APIResponse<ClipDTO>> getClipById(@AuthenticationPrincipal OAuth2User principal, @PathVariable Long id) {
if (principal == null) {
throw new NotAuthenticated("User is not authenticated");
}
public ResponseEntity<APIResponse<ClipDTO>> getClipById(@PathVariable Long id) {
Clip clip = clipService.getClipById(id);
if (clip == null) {
return ResponseEntity.notFound().build();

View File

@@ -73,7 +73,7 @@ public class GlobalExceptionHandler {
@ExceptionHandler(NotAuthenticated.class)
public ResponseEntity<APIResponse<Void>> handleNotAuthenticated(NotAuthenticated ex) {
logger.error("NotAuthenticated: {}", ex.getMessage());
APIResponse<Void> response = new APIResponse<>(ERROR, "User is not authenticated", null);
APIResponse<Void> response = new APIResponse<>(ERROR, ex.getMessage(), null);
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(response);
}
}

View File

@@ -0,0 +1,54 @@
package com.ddf.vodsystem.controllers;
import com.ddf.vodsystem.dto.APIResponse;
import com.ddf.vodsystem.dto.TokenDTO;
import com.ddf.vodsystem.entities.User;
import com.ddf.vodsystem.exceptions.NotAuthenticated;
import com.ddf.vodsystem.services.UserService;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.http.ResponseCookie;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/v1/auth/")
public class UserController {
private final UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
@GetMapping("/user")
public ResponseEntity<APIResponse<User>> user() {
User user = userService.getLoggedInUser();
if (user == null) {
throw new NotAuthenticated("User not authenticated");
}
return ResponseEntity.ok(
new APIResponse<>("success", "User retrieved successfully", user)
);
}
@PostMapping("/login")
public ResponseEntity<APIResponse<TokenDTO>> login(@RequestBody TokenDTO tokenDTO,
HttpServletResponse response) {
String jwt = userService.login(tokenDTO.getToken());
ResponseCookie cookie = ResponseCookie.from("token", jwt)
.httpOnly(true)
.maxAge(60 * 60 * 24)
.sameSite("None")
.secure(true)
.path("/")
.build();
response.addHeader("Set-Cookie", cookie.toString());
return ResponseEntity.ok(
new APIResponse<>("success", "Logged in successfully", new TokenDTO(jwt))
);
}
}