wip
All checks were successful
CI / Maven unit tests (push) Successful in 14s
CI / Build and push images (push) Has been skipped
CI / Deploy to server (push) Has been skipped

This commit is contained in:
2026-10-03 21:08:32 +01:00
parent c533257e98
commit 05361409b2
8 changed files with 79 additions and 27 deletions

View File

@@ -1,13 +1,16 @@
package com.ddf.vodsystem;
import com.ddf.vodsystem.dto.properties.AuthProperties;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@EnableScheduling
@EnableAsync
@EnableConfigurationProperties(AuthProperties.class)
public class VodSystemApplication {
/**

View File

@@ -20,7 +20,7 @@ import java.util.Optional;
public class UserController {
private final UserService userService;
@Value("${jwt.expiration}")
@Value("${app.security.expiration.jwt}")
private long jwtExpiration;
private static final String SUCCESS = "success";

View File

@@ -0,0 +1,23 @@
package com.ddf.vodsystem.dto.properties;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.validation.annotation.Validated;
import java.time.Duration;
@Validated
@ConfigurationProperties(prefix = "app.security")
public record AuthProperties (
@NotBlank @Size(min = 32) String jwtSecret,
@Valid @NotNull Expiration expiration
) {
public record Expiration (
@NotNull Duration jwt,
@NotNull Duration refreshToken,
@NotNull Duration tokenFamily
) {}
}

View File

@@ -0,0 +1,28 @@
package com.ddf.vodsystem.security;
import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.gson.GsonFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Collections;
@Configuration
public class GoogleAuthConfig {
/**
* Provides the verifier used to validate Google ID tokens issued for this application's client ID.
*
* @param googleClientId the OAuth client ID that tokens must be issued for
* @return the configured {@link GoogleIdTokenVerifier}
*/
@Bean
public GoogleIdTokenVerifier googleIdTokenVerifier(
@Value("${spring.security.oauth2.client.registration.google.client-id}") String googleClientId) {
return new GoogleIdTokenVerifier.Builder(new NetHttpTransport(), new GsonFactory())
.setAudience(Collections.singletonList(googleClientId))
.build();
}
}

View File

@@ -7,6 +7,7 @@ import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.ddf.vodsystem.dto.properties.AuthProperties;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.oauth2.jwt.JwtException;
import org.springframework.stereotype.Service;
@@ -20,10 +21,9 @@ public class JwtService {
private static final String USER_ID_CLAIM = "userId";
private static final String ISSUER = "vodsystem";
public JwtService(@Value("${jwt.secret.key}") String jwtSecretKey,
@Value("${jwt.expiration}") long jwtExpiration) {
this.jwtExpiration = jwtExpiration;
this.algorithm = Algorithm.HMAC256(jwtSecretKey);
public JwtService(AuthProperties props) {
this.jwtExpiration = props.expiration().jwt().toMillis();
this.algorithm = Algorithm.HMAC256(props.jwtSecret());
}
/**

View File

@@ -1,6 +1,7 @@
package com.ddf.vodsystem.services;
import com.ddf.vodsystem.dto.TokenPackage;
import com.ddf.vodsystem.dto.properties.AuthProperties;
import com.ddf.vodsystem.entities.RefreshToken;
import com.ddf.vodsystem.entities.TokenFamily;
import com.ddf.vodsystem.entities.User;
@@ -9,11 +10,7 @@ import com.ddf.vodsystem.repositories.UserRepository;
import com.ddf.vodsystem.security.JwtService;
import com.ddf.vodsystem.security.TokenService;
import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.gson.GsonFactory;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier;
@@ -24,7 +21,6 @@ import java.security.GeneralSecurityException;
import java.security.SecureRandom;
import java.time.Duration;
import java.time.Instant;
import java.util.Collections;
import java.util.HexFormat;
import java.util.Optional;
@@ -34,11 +30,8 @@ public class UserService {
private final UserRepository userRepository;
private final JwtService jwtService;
@Value("token-family.expiration")
private long tokenFamilyExpirationMs;
@Value("refresh-token.expiration")
private long refreshTokenExpirationMs;
private final long tokenFamilyExpirationMs;
private final long refreshTokenExpirationMs;
private static final SecureRandom SECURE_RANDOM = new SecureRandom();
private static final int REFRESH_GRACE_PERIOD_SECONDS = 5;
@@ -46,18 +39,16 @@ public class UserService {
public UserService(UserRepository userRepository,
JwtService jwtService,
@Value("${google.client.id}") String googleClientId,
GoogleIdTokenVerifier verifier,
AuthProperties props,
TokenService tokenService) {
this.userRepository = userRepository;
NetHttpTransport transport = new NetHttpTransport();
JsonFactory jsonFactory = new GsonFactory();
this.verifier = new GoogleIdTokenVerifier.Builder(transport, jsonFactory)
.setAudience(Collections.singletonList(googleClientId))
.build();
this.verifier = verifier;
this.jwtService = jwtService;
this.tokenService = tokenService;
this.refreshTokenExpirationMs = props.expiration().refreshToken().toMillis();
this.tokenFamilyExpirationMs = props.expiration().tokenFamily().toMillis();
}
/**

View File

@@ -20,13 +20,13 @@ spring.flyway.locations=classpath:db/migrations
spring.security.oauth2.client.registration.google.client-id=${GOOGLE_CLIENT_ID}
spring.security.oauth2.client.registration.google.client-secret=${GOOGLE_CLIENT_SECRET}
spring.security.oauth2.client.registration.google.scope=profile,email
jwt.secret.key=${JWT_SECRET_KEY}
app.security.jwt-secret=${JWT_SECRET_KEY}
# 1 Hour
jwt.expiration=3600000
app.security.expiration.jwt=3600000
# 7 days
refresh-token.expiration=604800000
app.security.expiration.refresh-token=604800000
# 90 days
token-family.expiration=7776000000
app.security.expiration.token-family=7776000000
# Frontend
frontend.url=${FRONTEND_URL}

View File

@@ -0,0 +1,7 @@
package com.ddf.vodsystem.services;
import static org.junit.jupiter.api.Assertions.*;
class UserServiceTest {
}