Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
96 commits
Select commit Hold shift + click to select a range
c9ff51d
test: add null/default value checks for User entity
lindaeskilsson Apr 8, 2026
5420a77
test: add lifecycle callback tests for User entity
lindaeskilsson Apr 8, 2026
3b80e90
test: add UserDetails tests
lindaeskilsson Apr 8, 2026
8cebc4d
test: add getAuthorties test
lindaeskilsson Apr 8, 2026
9414973
test: addAttachment and removeAttachment
lindaeskilsson Apr 8, 2026
575477d
test: getUploadedAttachments
lindaeskilsson Apr 8, 2026
796e27c
test: getUploadedAttachments
lindaeskilsson Apr 8, 2026
056713c
fix: rabbit comment
lindaeskilsson Apr 9, 2026
7f27cb3
test: test setUp and test on createUser
lindaeskilsson Apr 9, 2026
2084b61
test: test updateUser
lindaeskilsson Apr 9, 2026
dceac9a
test: test deleteUser
lindaeskilsson Apr 9, 2026
ccfdf95
test: add getbyemail, getuserEntitybyId, GetbyId, GetAllUsers. fix fr…
lindaeskilsson Apr 9, 2026
0fea6e0
test: add PetController tests for createPet endpoint
lindaeskilsson Apr 9, 2026
0d98cf1
test: add tests for GET /pets/{petId}
lindaeskilsson Apr 9, 2026
71da4c0
test: add tests for PUT /pets/{petId} and GET /pets/owner/{ownerId}
lindaeskilsson Apr 9, 2026
8db8572
feat: add OAuth2 resource server dependency in pom.xml
annikaholmqvist94 Apr 10, 2026
90517ef
feat: add JWT configuration properties in application.properties
annikaholmqvist94 Apr 10, 2026
c8c05ee
feat: add JwtProperties to load JWT configuration from application.pr…
annikaholmqvist94 Apr 10, 2026
56c6df5
feat: add JwtService for handling JWT creation and validation
annikaholmqvist94 Apr 10, 2026
3a6a56b
feat: add JwtAuthenticationFilter for token-based request authentication
annikaholmqvist94 Apr 11, 2026
74ca7b6
feat: configure SecurityConfig for JWT and CORS setup
annikaholmqvist94 Apr 11, 2026
8328c26
feat: implement CustomUserDetailsService for user authentication inte…
annikaholmqvist94 Apr 11, 2026
d606938
CustomUserDetailsService for user authentication integration
annikaholmqvist94 Apr 11, 2026
85928ae
test: add JwtService and CustomUserDetailsService mocks in VetControl…
annikaholmqvist94 Apr 11, 2026
201c64a
test: add JwtService and CustomUserDetailsService mocks in ActivityLo…
annikaholmqvist94 Apr 11, 2026
67000d1
test: add JwtService and CustomUserDetailsService mocks in ClinicCont…
annikaholmqvist94 Apr 11, 2026
295a52a
test: add JwtService and CustomUserDetailsService mocks in CommentCon…
annikaholmqvist94 Apr 11, 2026
aaee79b
test: add JwtService and CustomUserDetailsService mocks in MedicalRec…
annikaholmqvist94 Apr 11, 2026
bdd6c7e
Merge remote-tracking branch 'origin/main' into feat/spring-security-…
annikaholmqvist94 Apr 11, 2026
07bce62
test: add authentication setup in ActivityLogIntegrationTest and Atta…
annikaholmqvist94 Apr 11, 2026
69ce493
Test: integration tests for vet
TatjanaTrajkovic Apr 12, 2026
4c68a68
test: DELETE /pets/{petId}
lindaeskilsson Apr 13, 2026
243d567
Merge pull request #177 from ithsjava25/test/UserEntityTest
lindaeskilsson Apr 13, 2026
77c3379
Merge pull request #178 from ithsjava25/test/UserServiceTest
lindaeskilsson Apr 13, 2026
a401a6b
rabbit fixes
lindaeskilsson Apr 13, 2026
289fbd1
fix: specify UTF-8 charset for secret key generation in JwtService
annikaholmqvist94 Apr 13, 2026
184fbbe
fix: handle UsernameNotFoundException in JwtAuthenticationFilter
annikaholmqvist94 Apr 13, 2026
bc1a131
fix: validate secret key length for HS256 in JwtService
annikaholmqvist94 Apr 13, 2026
1d19d75
refactor: replace @RequestHeader with @AuthenticationPrincipal in Pet…
annikaholmqvist94 Apr 14, 2026
a7d1f66
refactor: use @AuthenticationPrincipal in ActivityLogController
annikaholmqvist94 Apr 14, 2026
c7ae70e
test: update ActivityLogControllerTest for Spring Security setup
annikaholmqvist94 Apr 14, 2026
8e1f665
test: remove redundant userId headers in ActivityLogIntegrationTest
annikaholmqvist94 Apr 14, 2026
7865e17
docs: add comprehensive API usage guide for frontend developers
annikaholmqvist94 Apr 14, 2026
965dcf1
test: clean up comments and update application-test.properties
annikaholmqvist94 Apr 14, 2026
ced6cae
Merge pull request #193 from ithsjava25/feat/spring-security-setup
annikaholmqvist94 Apr 14, 2026
f0c2d8e
Merge pull request #196 from ithsjava25/test/petControllerTest
lindaeskilsson Apr 14, 2026
4975a1d
fix: add missing security mocks to PetControllerTest and UserControll…
lindaeskilsson Apr 14, 2026
140301f
Test: GET /api/users and GET /api/users/{id}
lindaeskilsson Apr 13, 2026
8d61833
Test:POST /api/users, PUT /api/users/{id}
lindaeskilsson Apr 13, 2026
dad0c76
Test: DELETE /api/users/{id}
lindaeskilsson Apr 13, 2026
d5aafe0
rabbit fixes
lindaeskilsson Apr 14, 2026
2f200c6
rabbit fixes
lindaeskilsson Apr 14, 2026
c72684e
make CI work
lindaeskilsson Apr 14, 2026
3d8b5cc
fix: add missing security mocks to UserControllerTest
lindaeskilsson Apr 14, 2026
68bf569
fix: add missing security mocks to UserControllerTest
lindaeskilsson Apr 14, 2026
0a3b07d
Merge pull request #201 from ithsjava25/fix/pet-user-controller-test-…
lindaeskilsson Apr 14, 2026
e6c8235
Test: GET /api/users and GET /api/users/{id}
lindaeskilsson Apr 13, 2026
523d8bc
Test:POST /api/users, PUT /api/users/{id}
lindaeskilsson Apr 13, 2026
ff78a12
Test: DELETE /api/users/{id}
lindaeskilsson Apr 13, 2026
a34d43c
rabbit fixes
lindaeskilsson Apr 14, 2026
9d222d1
rabbit fixes
lindaeskilsson Apr 14, 2026
e1ec71e
make CI work
lindaeskilsson Apr 14, 2026
df63752
fix: add missing security mocks to UserControllerTest
lindaeskilsson Apr 14, 2026
ddb4faf
Test: GET /api/users and GET /api/users/{id}
lindaeskilsson Apr 13, 2026
73fcee9
Test:POST /api/users, PUT /api/users/{id}
lindaeskilsson Apr 13, 2026
05337fc
Test: DELETE /api/users/{id}
lindaeskilsson Apr 13, 2026
ae76172
rabbit fixes
lindaeskilsson Apr 14, 2026
c849dd9
rabbit fixes
lindaeskilsson Apr 14, 2026
1c10da8
make CI work
lindaeskilsson Apr 14, 2026
132210d
fix: add missing security mocks to UserControllerTest
lindaeskilsson Apr 14, 2026
0748bca
Test: GET /api/users and GET /api/users/{id}
lindaeskilsson Apr 13, 2026
e4aa50c
Test:POST /api/users, PUT /api/users/{id}
lindaeskilsson Apr 13, 2026
a1c0067
Test: DELETE /api/users/{id}
lindaeskilsson Apr 13, 2026
e0cb6e1
rabbit fixes
lindaeskilsson Apr 14, 2026
b2781e4
rabbit fixes
lindaeskilsson Apr 14, 2026
3a78cf1
make CI work
lindaeskilsson Apr 14, 2026
40dd395
fix: add missing security mocks to UserControllerTest
lindaeskilsson Apr 14, 2026
f20ff6c
Merge remote-tracking branch 'origin/UserControllerTest' into UserCon…
lindaeskilsson Apr 14, 2026
2ff5a80
fix: UserControllerTest
lindaeskilsson Apr 14, 2026
01d1ef6
feat: add AuthRequest DTO for authentication requests
annikaholmqvist94 Apr 14, 2026
45cb160
feat: add RegisterRequest DTO for user registration
annikaholmqvist94 Apr 14, 2026
e21c397
feat: add AuthResponse DTO for authentication responses
annikaholmqvist94 Apr 14, 2026
38c2e37
refactor: remove role field from RegisterRequest DTO
annikaholmqvist94 Apr 14, 2026
0c4686e
feat: enhance AuthRequest and RegisterRequest DTOs with improved vali…
annikaholmqvist94 Apr 14, 2026
dfed255
Minor fix
annikaholmqvist94 Apr 14, 2026
fc0b439
feat: add admin-only search user by email endpoint #132
lindaeskilsson Apr 14, 2026
49c4da7
fix: remove email from log to avoid PII exposure
lindaeskilsson Apr 14, 2026
a8566f4
Merge pull request #202 from ithsjava25/feat/security-auth-and-register
annikaholmqvist94 Apr 14, 2026
1d07712
Merge pull request #200 from ithsjava25/UserControllerTest
lindaeskilsson Apr 14, 2026
8deee0c
Merge pull request #203 from ithsjava25/feat/search-user-by-email
lindaeskilsson Apr 14, 2026
bcbab8e
Test: integration tests for vet
TatjanaTrajkovic Apr 12, 2026
5f7d393
Test: improve integration tests for vet
TatjanaTrajkovic Apr 14, 2026
6d91024
Merge remote-tracking branch 'origin/test/integration_tests_vet' into…
TatjanaTrajkovic Apr 14, 2026
dc8d710
Test: improve integration tests for vet
TatjanaTrajkovic Apr 14, 2026
4235cfe
Test: improve after coderabbit suggestions integration tests for vet
TatjanaTrajkovic Apr 14, 2026
8b0d484
Test: changes and improve code after coderabbit suggestions integrati…
TatjanaTrajkovic Apr 14, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
812 changes: 812 additions & 0 deletions API.md

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>s3</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
import org.example.vet1177.dto.response.activitylog.ActivityLogResponse;
import org.example.vet1177.entities.User;
import org.example.vet1177.services.ActivityLogService;
import org.example.vet1177.services.UserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.*;

import java.util.List;
Expand All @@ -18,26 +18,22 @@ public class ActivityLogController {
private static final Logger log = LoggerFactory.getLogger(ActivityLogController.class);

private final ActivityLogService activityLogService;
private final UserService userService;

public ActivityLogController(ActivityLogService activityLogService,
UserService userService) {
public ActivityLogController(ActivityLogService activityLogService) {
this.activityLogService = activityLogService;
this.userService = userService;
}

// Hämta alla logs för ett MedicalRecord
@GetMapping("/record/{recordId}")
public List<ActivityLogResponse> getLogsByRecord(
@PathVariable UUID recordId,
@RequestHeader("userId") UUID userId
@AuthenticationPrincipal User currentUser
) {
log.info("GET /api/activity-logs/record/{}", recordId);
User user = userService.getUserEntityById(userId);

return activityLogService.getByRecord(recordId, user)
return activityLogService.getByRecord(recordId, currentUser)
.stream()
.map(ActivityLogResponse::from)
.toList();
}
}
}
39 changes: 19 additions & 20 deletions src/main/java/org/example/vet1177/controller/PetController.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
import org.example.vet1177.services.PetService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.example.vet1177.services.UserService;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.*;

import java.util.List;
Expand All @@ -22,44 +22,42 @@ public class PetController {
private static final Logger log = LoggerFactory.getLogger(PetController.class);

private final PetService petService;
private final UserService userService;

public PetController(PetService petService, UserService userService) {
public PetController(PetService petService) {
this.petService = petService;
this.userService = userService;
}

//POST / pets - skapa nytt djur
//POST /pets - skapa nytt djur
@PostMapping
public PetResponse createPet(
// TODO: Ersätt med användare från autentiserad kontext (t.ex. JWT / Spring Security)
@RequestHeader UUID currentUserId,
@AuthenticationPrincipal User currentUser,
@RequestParam(required = false) UUID ownerId,
@Valid @RequestBody PetRequest request
) {
log.info("POST /pets - creating pet for currentUserId={} ownerId={}", currentUserId, ownerId);
Pet saved = petService.createPet(currentUserId, ownerId, request);
log.info("POST /pets - creating pet for userId={} ownerId={}", currentUser.getId(), ownerId);
Pet saved = petService.createPet(currentUser.getId(), ownerId, request);
return toResponse(saved);
}

// GET / pets/{petId} - hämta ett specifikt djur
// GET /pets/{petId} - hämta ett specifikt djur
@GetMapping("/{petId}")
public ResponseEntity<PetResponse> getPetById(
@RequestHeader UUID currentUserId,
@AuthenticationPrincipal User currentUser,
@PathVariable UUID petId
) {
User currentUser = userService.getUserEntityById(currentUserId);
log.info("GET /pets/{}", petId);
Pet pet = petService.getPetById(petId, currentUser);
return ResponseEntity.ok(toResponse(pet));
}

// GET/pets/owner/{ownerId} - hämta alla djur för en ägare
// GET /pets/owner/{ownerId} - hämta alla djur för en ägare
@GetMapping("/owner/{ownerId}")
public ResponseEntity<List<PetResponse>> getPetsByOwner(
@RequestHeader UUID currentUserId,
@AuthenticationPrincipal User currentUser,
@PathVariable UUID ownerId
) {
List<PetResponse> pets = petService.getPetsByOwner(currentUserId, ownerId)
log.info("GET /pets/owner/{}", ownerId);
List<PetResponse> pets = petService.getPetsByOwner(currentUser.getId(), ownerId)
.stream()
.map(this::toResponse)
.toList();
Expand All @@ -69,21 +67,22 @@ public ResponseEntity<List<PetResponse>> getPetsByOwner(
// PUT /pets/{petId} - uppdatera ett djur
@PutMapping("/{petId}")
public ResponseEntity<PetResponse> updatePet(
@RequestHeader UUID currentUserId,
@AuthenticationPrincipal User currentUser,
@PathVariable UUID petId,
@Valid @RequestBody PetRequest request
) {
Pet updated = petService.updatePet(currentUserId, petId, request);
log.info("PUT /pets/{}", petId);
Pet updated = petService.updatePet(currentUser.getId(), petId, request);
return ResponseEntity.ok(toResponse(updated));
}

// DELETE /pets/{petId} - radera ett djur
@DeleteMapping("/{petId}")
public ResponseEntity<Void> deletePet(
@RequestHeader UUID currentUserId,
@AuthenticationPrincipal User currentUser,
@PathVariable UUID petId
) {
User currentUser = userService.getUserEntityById(currentUserId);
log.info("DELETE /pets/{}", petId);
petService.deletePet(petId, currentUser);
return ResponseEntity.noContent().build();
}
Expand All @@ -103,4 +102,4 @@ private PetResponse toResponse(Pet pet) {
);
}

}
}
10 changes: 10 additions & 0 deletions src/main/java/org/example/vet1177/controller/UserController.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.example.vet1177.dto.request.user.UserUpdateRequest;
import org.springframework.security.access.prepost.PreAuthorize;

import java.util.List;
import java.util.UUID;
Expand Down Expand Up @@ -42,6 +43,15 @@ public ResponseEntity<UserResponse> getUserById(@PathVariable UUID id) {
return ResponseEntity.ok(user);
}

// GET /users/search?email= - Sök användare på email (endast admin)
@GetMapping("/search")
@PreAuthorize("hasRole('ADMIN')")
public ResponseEntity<UserResponse> searchByEmail(@RequestParam String email) {
log.info("GET /api/users/search");
UserResponse user = userService.searchByEmail(email);
return ResponseEntity.ok(user);
}

//POST /users - skapa ny användare
@PostMapping
public ResponseEntity<UserResponse> createUser(@Valid @RequestBody UserRequest request) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package org.example.vet1177.security;

import org.example.vet1177.repository.UserRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

/**
* Bryggan mellan Spring Security och vår databas.
*
* Spring Security behöver veta hur man hämtar en användare givet ett "användarnamn".
* I vårt fall är "användarnamnet" email-adressen (det som står i JWT:ns subject-claim).
*
* Flödet:
* JWT-token innehåller sub="sara@vet.se"
* ↓
* JwtAuthenticationFilter anropar loadUserByUsername("sara@vet.se")
* ↓
* Vi söker i databasen: userRepository.findByEmail("sara@vet.se")
* ↓
* Returnerar User-objektet (som implementerar UserDetails)
* ↓
* Spring Security sätter det i SecurityContext → @AuthenticationPrincipal fungerar
*/
@Service
public class CustomUserDetailsService implements UserDetailsService {

private static final Logger log = LoggerFactory.getLogger(CustomUserDetailsService.class);

private final UserRepository userRepository;

public CustomUserDetailsService(UserRepository userRepository) {
this.userRepository = userRepository;
}

@Override
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
log.debug("Loading user by email={}", email);


return userRepository.findByEmail(email)
.orElseThrow(() -> {
log.warn("User not found during authentication");
return new UsernameNotFoundException("Användare hittades inte");
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
package org.example.vet1177.security;

import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.oauth2.jwt.JwtException;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;

/**
* Filter som körs EN gång per HTTP-request (OncePerRequestFilter).
*
* Vad händer steg för steg:
*
* [Klient] → HTTP Request med "Authorization: Bearer eyJhbG..."
* ↓
* [JwtAuthenticationFilter]
* 1. Läser Authorization-headern
* 2. Extraherar token-strängen (allt efter "Bearer ")
* 3. Avkodar token via JwtService → får email + roll
* 4. Laddar User från DB via CustomUserDetailsService
* 5. Skapar ett Authentication-objekt och sätter det i SecurityContext
* ↓
* [Spring Security]
* Kollar SecurityContext: finns en autentiserad användare?
* Om ja → kontrollerar att användaren har rätt roll för endpointen
* Om nej → returnerar 401 Unauthorized
* ↓
* [Controller]
* @AuthenticationPrincipal User currentUser ← hämtas från SecurityContext
*/
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {

private static final Logger log = LoggerFactory.getLogger(JwtAuthenticationFilter.class);

private final JwtService jwtService;
private final CustomUserDetailsService userDetailsService;

public JwtAuthenticationFilter(JwtService jwtService, CustomUserDetailsService userDetailsService) {
this.jwtService = jwtService;
this.userDetailsService = userDetailsService;
}

@Override
protected void doFilterInternal(
HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {

// 1. Läs Authorization-headern
// Formatet är: "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
String authHeader = request.getHeader("Authorization");

// Om headern saknas eller inte börjar med "Bearer " → skippa filtret.
// Requesten släpps vidare i kedjan. Om endpointen kräver auth
// kommer Spring Security att returnera 401 automatiskt.
if (authHeader == null || !authHeader.startsWith("Bearer ")) {
filterChain.doFilter(request, response);
return;
}

// 2. Extrahera token-strängen (ta bort "Bearer " som är 7 tecken)
String token = authHeader.substring(7);

try {
// 3. Avkoda och validera token.
// Om signaturen inte stämmer eller token har gått ut kastar decode() JwtException.
Jwt jwt = jwtService.decode(token);

// 4. Hämta email från token (subject-claim)
String email = jwt.getSubject();

// Kolla att vi inte redan har autentiserat denna request
// (kan hända om flera filter kör i kedjan)
if (email != null && SecurityContextHolder.getContext().getAuthentication() == null) {

// 5. Ladda det fulla User-objektet från databasen.
// Vi behöver hela entiteten (med id, klinik, roll) för @AuthenticationPrincipal.
var userDetails = userDetailsService.loadUserByUsername(email);

// 6. Skapa ett Authentication-objekt.
// UsernamePasswordAuthenticationToken är Springs standardklass för "en autentiserad användare".
// - Första argumentet (principal) → User-objektet (det som @AuthenticationPrincipal ger)
// - Andra argumentet (credentials) → null (vi behöver inte lösenordet, token räcker)
// - Tredje argumentet (authorities) → rollerna (ROLE_VET, ROLE_ADMIN, etc.)
var authentication = new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities()
);

// Kopplar request-detaljer (IP-adress, session-id) till autentiseringen — för loggning.
authentication.setDetails(
new WebAuthenticationDetailsSource().buildDetails(request)
);

// 7. Sätt autentiseringen i SecurityContext.
// Från och med nu "vet" Spring Security att det finns en inloggad användare.
// Alla controllers kan hämta den via @AuthenticationPrincipal.
SecurityContextHolder.getContext().setAuthentication(authentication);

log.debug("Authenticated user email={} via JWT", email);
}

} catch (JwtException e) {
// Token är ogiltig (felaktig signatur, utgången, korrupt).
// Vi loggar och släpper vidare — Spring Security returnerar 401 automatiskt
// eftersom SecurityContext förblir tom.
log.warn("Invalid JWT token: {}", e.getMessage());
} catch (UsernameNotFoundException e) {
// Token är giltig men användaren finns inte längre i databasen
// (t.ex. raderad av admin medan tokenen fortfarande gäller).
log.warn("User from JWT no longer exists in database");
}

// Släpp vidare requesten till nästa filter i kedjan (och sedan till controllern)
filterChain.doFilter(request, response);
}
}
22 changes: 22 additions & 0 deletions src/main/java/org/example/vet1177/security/JwtProperties.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package org.example.vet1177.security;

import org.springframework.boot.context.properties.ConfigurationProperties;

/**
* Läser JWT-konfiguration från application.properties.
*
* jwt.secret-key → den hemliga nyckeln som används för att signera/verifiera tokens (HMAC SHA-256)
* jwt.expiration-ms → hur länge en token är giltig i millisekunder (86400000 = 24 timmar)
*/
@ConfigurationProperties(prefix = "jwt")
public class JwtProperties {

private String secretKey;
private long expirationMs;

public String getSecretKey() { return secretKey; }
public void setSecretKey(String secretKey) { this.secretKey = secretKey; }

public long getExpirationMs() { return expirationMs; }
public void setExpirationMs(long expirationMs) { this.expirationMs = expirationMs; }
}
Loading