diff --git a/.gitignore b/.gitignore index 549e00a..4e0b5cf 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,9 @@ target/ !.mvn/wrapper/maven-wrapper.jar !**/src/main/**/target/ !**/src/test/**/target/ +logs/ +*.log +secret.env ### STS ### .apt_generated diff --git a/docker-compose.yml b/docker-compose.yml index ccc55e4..a3d2810 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,6 +1,7 @@ services: backend: image: openjdk:25-ea-4-jdk-oraclelinux9 + container_name: auth ports: - "8080:8080" env_file: @@ -9,13 +10,15 @@ services: - auth_db environment: - SPRING_DATASOURCE_URL=jdbc:postgresql://auth_db:5432/authDB + - SPRING_DATA_REDIS_HOST=redis_cache volumes: - ./target:/app - ./logs:/logs command: [ "java", "-jar", "/app/auth-0.0.1-SNAPSHOT.jar" ] auth_db: - image: postgres:latest + image: postgres:14.17 + container_name: auth_db environment: POSTGRES_PASSWORD: 1234 POSTGRES_USER: postgres @@ -24,13 +27,15 @@ services: - "5432:5432" loki: - image: grafana/loki:latest + image: grafana/loki:3.5.0 + container_name: loki ports: - "3100:3100" command: -config.file=/etc/loki/local-config.yaml promtail: - image: grafana/promtail:latest + image: grafana/promtail:3.5.0 + container_name: promtail volumes: - ./promtail-config.yml:/etc/promtail/promtail-config.yaml - ./logs:/logs @@ -39,8 +44,23 @@ services: - loki grafana: - image: grafana/grafana:latest + image: grafana/grafana:11.6.1 + container_name: grafana ports: - "3000:3000" depends_on: - loki + + + redis_cache: + image: redis:7.4.3 + container_name: redisCache + ports: + - "6379:6379" + + redisinsight: + image: redis/redisinsight:2.68 + container_name: redisInsight + ports: + - "5540:5540" + restart: always \ No newline at end of file diff --git a/src/main/java/com/podzilla/auth/AuthApplication.java b/src/main/java/com/podzilla/auth/AuthApplication.java index cb6eb42..920bdd3 100644 --- a/src/main/java/com/podzilla/auth/AuthApplication.java +++ b/src/main/java/com/podzilla/auth/AuthApplication.java @@ -2,8 +2,10 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cache.annotation.EnableCaching; @SpringBootApplication +@EnableCaching public class AuthApplication { public static void main(final String[] args) { diff --git a/src/main/java/com/podzilla/auth/dto/CustomUserDetails.java b/src/main/java/com/podzilla/auth/dto/CustomUserDetails.java new file mode 100644 index 0000000..e1db335 --- /dev/null +++ b/src/main/java/com/podzilla/auth/dto/CustomUserDetails.java @@ -0,0 +1,42 @@ +package com.podzilla.auth.dto; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; + +import java.util.Collection; +import java.util.Set; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class CustomUserDetails implements UserDetails { + + private String username; + private String password; + private Set authorities; + + public CustomUserDetails() { + // No-arg constructor required by Jackson + } + + public CustomUserDetails(final String username, final String password, + final Set authorities) { + this.username = username; + this.password = password; + this.authorities = authorities; + } + + @Override + public String getUsername() { + return username; + } + + @Override + public String getPassword() { + return password; + } + + @Override + public Collection getAuthorities() { + return authorities; + } +} diff --git a/src/main/java/com/podzilla/auth/exception/GlobalExceptionHandler.java b/src/main/java/com/podzilla/auth/exception/GlobalExceptionHandler.java index 527126e..19eb55d 100644 --- a/src/main/java/com/podzilla/auth/exception/GlobalExceptionHandler.java +++ b/src/main/java/com/podzilla/auth/exception/GlobalExceptionHandler.java @@ -2,11 +2,31 @@ import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.core.AuthenticationException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; +import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; @RestControllerAdvice -public class GlobalExceptionHandler { +public class GlobalExceptionHandler extends ResponseEntityExceptionHandler { + + + @ExceptionHandler(AccessDeniedException.class) + public ResponseEntity handleAccessDeniedException( + final AccessDeniedException exception) { + return ResponseEntity.status(HttpStatus.FORBIDDEN) + .body(new ErrorResponse(exception.getMessage(), + HttpStatus.FORBIDDEN)); + } + + @ExceptionHandler(AuthenticationException.class) + public ResponseEntity handleAuthenticationException( + final AuthenticationException exception) { + return ResponseEntity.status(HttpStatus.UNAUTHORIZED) + .body(new ErrorResponse(exception.getMessage(), + HttpStatus.UNAUTHORIZED)); + } @ExceptionHandler(NotFoundException.class) public ResponseEntity handleNotFoundException( diff --git a/src/main/java/com/podzilla/auth/model/RefreshToken.java b/src/main/java/com/podzilla/auth/model/RefreshToken.java index 7f7da62..3405a08 100644 --- a/src/main/java/com/podzilla/auth/model/RefreshToken.java +++ b/src/main/java/com/podzilla/auth/model/RefreshToken.java @@ -9,9 +9,11 @@ import jakarta.persistence.ManyToOne; import jakarta.persistence.Column; import jakarta.persistence.Table; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Getter; -import lombok.NoArgsConstructor; import lombok.Setter; +import lombok.NoArgsConstructor; import org.springframework.data.annotation.CreatedDate; import org.springframework.data.jpa.domain.support.AuditingEntityListener; @@ -21,8 +23,10 @@ @Entity @Table(name = "refresh_tokens") @Getter +@Builder @Setter @NoArgsConstructor +@AllArgsConstructor @EntityListeners(AuditingEntityListener.class) public class RefreshToken { diff --git a/src/main/java/com/podzilla/auth/redis/RedisCacheConfig.java b/src/main/java/com/podzilla/auth/redis/RedisCacheConfig.java new file mode 100644 index 0000000..93ed31a --- /dev/null +++ b/src/main/java/com/podzilla/auth/redis/RedisCacheConfig.java @@ -0,0 +1,38 @@ +package com.podzilla.auth.redis; + +import com.podzilla.auth.dto.CustomUserDetails; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.cache.RedisCacheConfiguration; +import org.springframework.data.redis.cache.RedisCacheManager; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; +import org.springframework.data.redis.serializer.RedisSerializationContext; + +import java.time.Duration; + +@Configuration +public class RedisCacheConfig { + + private static final int CACHE_TTL = 60 * 60; + + @Bean + public RedisCacheManager cacheManager( + final RedisConnectionFactory redisConnectionFactory) { + + RedisCacheConfiguration defaultConfig = RedisCacheConfiguration + .defaultCacheConfig() + .entryTtl(Duration.ofMinutes(CACHE_TTL)) + .disableCachingNullValues() + .serializeValuesWith( + RedisSerializationContext. + SerializationPair. + fromSerializer( + new Jackson2JsonRedisSerializer<>( + CustomUserDetails.class))); + + return RedisCacheManager.builder(redisConnectionFactory) + .cacheDefaults(defaultConfig) + .build(); + } +} diff --git a/src/main/java/com/podzilla/auth/security/JWTAuthenticationFilter.java b/src/main/java/com/podzilla/auth/security/JWTAuthenticationFilter.java index 34d1297..a2d2855 100644 --- a/src/main/java/com/podzilla/auth/security/JWTAuthenticationFilter.java +++ b/src/main/java/com/podzilla/auth/security/JWTAuthenticationFilter.java @@ -62,7 +62,7 @@ protected void doFilterInternal(final HttpServletRequest request, context.setAuthentication(authToken); SecurityContextHolder.setContext(context); - + LOGGER.info("User {} authenticated", userEmail); } catch (Exception e) { LOGGER.error("Invalid JWT token: {}", e.getMessage()); } diff --git a/src/main/java/com/podzilla/auth/security/RestAuthenticationEntryPoint.java b/src/main/java/com/podzilla/auth/security/RestAuthenticationEntryPoint.java deleted file mode 100644 index 2351372..0000000 --- a/src/main/java/com/podzilla/auth/security/RestAuthenticationEntryPoint.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.podzilla.auth.security; - -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import org.springframework.security.core.AuthenticationException; -import org.springframework.security.web.AuthenticationEntryPoint; -import org.springframework.stereotype.Component; - -import java.io.IOException; - -@Component -public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint { - - @Override - public void commence(final HttpServletRequest request, - final HttpServletResponse response, - final AuthenticationException authException) - throws IOException { - response.sendError(HttpServletResponse.SC_UNAUTHORIZED, - "Authentication Failed"); - } -} diff --git a/src/main/java/com/podzilla/auth/security/SecurityConfig.java b/src/main/java/com/podzilla/auth/security/SecurityConfig.java index d8b83f0..fef3d0c 100644 --- a/src/main/java/com/podzilla/auth/security/SecurityConfig.java +++ b/src/main/java/com/podzilla/auth/security/SecurityConfig.java @@ -2,7 +2,6 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.http.HttpMethod; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.ProviderManager; import org.springframework.security.authentication.dao.DaoAuthenticationProvider; @@ -35,22 +34,20 @@ SecurityFilterChain securityFilterChain(final HttpSecurity http) .csrf(AbstractHttpConfigurer::disable) .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class) - .exceptionHandling(exceptionHandling -> - exceptionHandling - .authenticationEntryPoint( - new RestAuthenticationEntryPoint()) - ) .authorizeHttpRequests((auth) -> - auth.requestMatchers( - HttpMethod.GET, "public_resource") + auth + .requestMatchers("/auth/login") + .permitAll() + .requestMatchers("/auth/register") + .permitAll() + .requestMatchers("/auth/refresh-token") .permitAll() - .requestMatchers("/auth/**").permitAll() .requestMatchers("/admin/**") .hasRole("ADMIN") .requestMatchers("/swagger-ui/**", - "/v3/api-docs/**").permitAll() + "/v3/api-docs/**") + .permitAll() .anyRequest().authenticated() - ) .sessionManagement(s -> s .sessionCreationPolicy( diff --git a/src/main/java/com/podzilla/auth/service/AuthenticationService.java b/src/main/java/com/podzilla/auth/service/AuthenticationService.java index 406dd52..aa9f95d 100644 --- a/src/main/java/com/podzilla/auth/service/AuthenticationService.java +++ b/src/main/java/com/podzilla/auth/service/AuthenticationService.java @@ -65,22 +65,31 @@ public String login(final LoginRequest loginRequest, } public void registerAccount(final SignupRequest signupRequest) { + if (signupRequest.getPassword().isEmpty()) { + throw new ValidationException("Password cannot be empty."); + } + if (userRepository.existsByEmail(signupRequest.getEmail())) { throw new ValidationException("Email already in use."); } - User account = new User( - signupRequest.getName(), - signupRequest.getEmail(), - passwordEncoder.encode(signupRequest.getPassword())); + User account = + User.builder() + .name(signupRequest.getName()) + .email(signupRequest.getEmail()) + .password( + passwordEncoder.encode( + signupRequest.getPassword())) + .build(); Role role = roleRepository.findByErole(ERole.ROLE_USER).orElse(null); account.setRoles(Collections.singleton(role)); userRepository.save(account); } - public void logoutUser(final HttpServletResponse response) { + public void logoutUser( + final HttpServletResponse response) { tokenService.removeAccessTokenFromCookie(response); - tokenService.removeRefreshTokenFromCookie(response); + tokenService.removeRefreshTokenFromCookieAndExpire(response); } public String refreshToken(final HttpServletRequest request, diff --git a/src/main/java/com/podzilla/auth/service/CustomUserDetailsService.java b/src/main/java/com/podzilla/auth/service/CustomUserDetailsService.java index aa23490..5af441f 100644 --- a/src/main/java/com/podzilla/auth/service/CustomUserDetailsService.java +++ b/src/main/java/com/podzilla/auth/service/CustomUserDetailsService.java @@ -1,9 +1,11 @@ package com.podzilla.auth.service; +import com.podzilla.auth.dto.CustomUserDetails; import com.podzilla.auth.exception.NotFoundException; import com.podzilla.auth.model.User; import com.podzilla.auth.repository.UserRepository; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.annotation.Cacheable; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; @@ -24,6 +26,7 @@ public CustomUserDetailsService(final UserRepository userRepository) { } @Override + @Cacheable(value = "userDetails", key = "#email") public UserDetails loadUserByUsername(final String email) { User user = userRepository.findByEmail(email) .orElseThrow(() -> @@ -37,7 +40,7 @@ public UserDetails loadUserByUsername(final String email) { role.getErole().name())) .collect(Collectors.toSet()); - return new org.springframework.security.core.userdetails.User( + return new CustomUserDetails( user.getEmail(), user.getPassword(), authorities diff --git a/src/main/java/com/podzilla/auth/service/JWTService.java b/src/main/java/com/podzilla/auth/service/JWTService.java deleted file mode 100644 index e8577dc..0000000 --- a/src/main/java/com/podzilla/auth/service/JWTService.java +++ /dev/null @@ -1,185 +0,0 @@ -package com.podzilla.auth.service; - -import com.podzilla.auth.exception.ValidationException; -import com.podzilla.auth.model.RefreshToken; -import com.podzilla.auth.model.User; -import com.podzilla.auth.repository.RefreshTokenRepository; -import com.podzilla.auth.repository.UserRepository; -import io.jsonwebtoken.Claims; -import io.jsonwebtoken.JwtException; -import io.jsonwebtoken.Jwts; -import io.jsonwebtoken.io.Decoders; -import io.jsonwebtoken.security.Keys; -import jakarta.servlet.http.Cookie; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Service; -import org.springframework.web.util.WebUtils; - -import javax.crypto.SecretKey; -import java.time.Instant; -import java.time.temporal.TemporalAmount; -import java.util.Date; -import java.util.UUID; - -@Service -public class JWTService { - - // set in .env - @Value("${jwt.token.secret}") - private String secret; - - @Value("${jwt.token.expires}") - private Long jwtExpiresMinutes; - - private Claims claims; - - private static final Integer ACCESS_TOKEN_EXPIRATION_TIME = 60 * 1000; - private static final Integer ACCESS_TOKEN_COOKIE_EXPIRATION_TIME = 60 * 30; - private static final TemporalAmount REFRESH_TOKEN_EXPIRATION_TIME = - java.time.Duration.ofDays(10); - private static final Integer REFRESH_TOKEN_COOKIE_EXPIRATION_TIME = - 60 * 60 * 24 * 10; - - private final UserRepository userRepository; - private final RefreshTokenRepository refreshTokenRepository; - - public JWTService(final UserRepository userRepository, - final RefreshTokenRepository refreshTokenRepository) { - this.userRepository = userRepository; - this.refreshTokenRepository = refreshTokenRepository; - } - - public void generateAccessToken(final String email, - final HttpServletResponse response) { - String jwt = Jwts.builder() - .subject(email) - .issuedAt(new Date(System.currentTimeMillis())) - .expiration(new Date(System.currentTimeMillis() - + jwtExpiresMinutes * ACCESS_TOKEN_EXPIRATION_TIME)) - .signWith(getSignInKey()) - .compact(); - - Cookie cookie = new Cookie("accessToken", jwt); - cookie.setHttpOnly(true); - cookie.setSecure(true); - cookie.setPath("/"); - cookie.setMaxAge(ACCESS_TOKEN_COOKIE_EXPIRATION_TIME); - response.addCookie(cookie); - } - - public void generateRefreshToken(final String email, - final HttpServletResponse response) { - User user = userRepository.findByEmail(email) - .orElseThrow(() -> new ValidationException("User not found")); - RefreshToken userRefreshToken = - refreshTokenRepository.findByUserIdAndExpiresAtAfter( - user.getId(), Instant.now()).orElse(null); - - if (userRefreshToken == null) { - userRefreshToken = new RefreshToken(); - userRefreshToken.setUser(user); - userRefreshToken.setCreatedAt(Instant.now()); - userRefreshToken.setExpiresAt(Instant.now().plus( - REFRESH_TOKEN_EXPIRATION_TIME)); - refreshTokenRepository.save(userRefreshToken); - } - - String refreshTokenString = userRefreshToken.getId().toString(); - addRefreshTokenToCookie(refreshTokenString, response); - } - - public String renewRefreshToken(final String refreshToken, - final HttpServletResponse response) { - RefreshToken token = - refreshTokenRepository - .findByIdAndExpiresAtAfter( - UUID.fromString(refreshToken), Instant.now()) - .orElseThrow(() -> - new ValidationException( - "Invalid refresh token")); - - token.setExpiresAt(Instant.now()); - refreshTokenRepository.save(token); - - RefreshToken newRefreshToken = new RefreshToken(); - newRefreshToken.setUser(token.getUser()); - newRefreshToken.setCreatedAt(Instant.now()); - newRefreshToken.setExpiresAt(Instant.now().plus( - REFRESH_TOKEN_EXPIRATION_TIME)); - refreshTokenRepository.save(newRefreshToken); - - String newRefreshTokenString = newRefreshToken.getId().toString(); - addRefreshTokenToCookie(newRefreshTokenString, response); - - return token.getUser().getEmail(); - } - - private void addRefreshTokenToCookie(final String refreshToken, - final HttpServletResponse response) { - Cookie cookie = new Cookie("refreshToken", refreshToken); - cookie.setHttpOnly(true); - cookie.setSecure(true); - cookie.setPath("/api/auth/refresh-token"); - cookie.setMaxAge(REFRESH_TOKEN_COOKIE_EXPIRATION_TIME); - response.addCookie(cookie); - } - - public String getAccessTokenFromCookie(final HttpServletRequest request) { - Cookie cookie = WebUtils.getCookie(request, "accessToken"); - if (cookie != null) { - return cookie.getValue(); - } - return null; - - } - - public String getRefreshTokenFromCookie(final HttpServletRequest request) { - Cookie cookie = WebUtils.getCookie(request, "refreshToken"); - if (cookie != null) { - return cookie.getValue(); - } - return null; - } - - public void validateAccessToken(final String token) { - try { - claims = Jwts.parser() - .verifyWith(getSignInKey()) - .build() - .parseSignedClaims(token) - .getPayload(); - - - } catch (JwtException e) { - throw new ValidationException(e.getMessage()); - } - } - - public void removeAccessTokenFromCookie( - final HttpServletResponse response) { - Cookie cookie = new Cookie("JWT", null); - cookie.setPath("/"); - - response.addCookie(cookie); - } - - public void removeRefreshTokenFromCookie( - final HttpServletResponse response) { - Cookie cookie = new Cookie("refreshToken", null); - cookie.setPath("/api/auth/refresh-token"); - - response.addCookie(cookie); - } - - private SecretKey getSignInKey() { - byte[] keyBytes = Decoders.BASE64.decode(this.secret); - return Keys.hmacShaKeyFor(keyBytes); - } - - public String extractEmail() { - return claims.getSubject(); - } - -} diff --git a/src/main/java/com/podzilla/auth/service/TokenService.java b/src/main/java/com/podzilla/auth/service/TokenService.java index 9fb564c..bd186ca 100644 --- a/src/main/java/com/podzilla/auth/service/TokenService.java +++ b/src/main/java/com/podzilla/auth/service/TokenService.java @@ -1,5 +1,6 @@ package com.podzilla.auth.service; +import com.podzilla.auth.exception.ValidationException; import com.podzilla.auth.model.RefreshToken; import com.podzilla.auth.model.User; import com.podzilla.auth.repository.RefreshTokenRepository; @@ -9,11 +10,9 @@ import io.jsonwebtoken.Jwts; import io.jsonwebtoken.io.Decoders; import io.jsonwebtoken.security.Keys; -import jakarta.persistence.EntityExistsException; import jakarta.servlet.http.Cookie; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; -import jakarta.validation.ValidationException; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.web.util.WebUtils; @@ -76,17 +75,18 @@ public void generateAccessToken(final String email, public void generateRefreshToken(final String email, final HttpServletResponse response) { User user = userRepository.findByEmail(email) - .orElseThrow(() -> new EntityExistsException("User not found")); + .orElseThrow(() -> new ValidationException("User not found")); RefreshToken userRefreshToken = refreshTokenRepository.findByUserIdAndExpiresAtAfter( user.getId(), Instant.now()).orElse(null); if (userRefreshToken == null) { - userRefreshToken = new RefreshToken(); - userRefreshToken.setUser(user); - userRefreshToken.setCreatedAt(Instant.now()); - userRefreshToken.setExpiresAt(Instant.now().plus( - REFRESH_TOKEN_EXPIRATION_TIME)); + userRefreshToken = + RefreshToken.builder() + .user(user) + .createdAt(Instant.now()) + .expiresAt(Instant.now().plus( + REFRESH_TOKEN_EXPIRATION_TIME)).build(); refreshTokenRepository.save(userRefreshToken); } @@ -107,11 +107,12 @@ public String renewRefreshToken(final String refreshToken, token.setExpiresAt(Instant.now()); refreshTokenRepository.save(token); - RefreshToken newRefreshToken = new RefreshToken(); - newRefreshToken.setUser(token.getUser()); - newRefreshToken.setCreatedAt(Instant.now()); - newRefreshToken.setExpiresAt(Instant.now().plus( - REFRESH_TOKEN_EXPIRATION_TIME)); + RefreshToken newRefreshToken = + RefreshToken.builder() + .user(token.getUser()) + .createdAt(Instant.now()) + .expiresAt(Instant.now().plus( + REFRESH_TOKEN_EXPIRATION_TIME)).build(); refreshTokenRepository.save(newRefreshToken); String newRefreshTokenString = newRefreshToken.getId().toString(); @@ -147,7 +148,7 @@ public String getRefreshTokenFromCookie(final HttpServletRequest request) { return null; } - public void validateAccessToken(final String token) throws JwtException { + public void validateAccessToken(final String token) { try { claims = Jwts.parser() .verifyWith(getSignInKey()) @@ -157,7 +158,7 @@ public void validateAccessToken(final String token) throws JwtException { } catch (JwtException e) { - throw new JwtException(e.getMessage()); + throw new ValidationException(e.getMessage()); } } @@ -169,14 +170,31 @@ public void removeAccessTokenFromCookie( response.addCookie(cookie); } - public void removeRefreshTokenFromCookie( + public void removeRefreshTokenFromCookieAndExpire( final HttpServletResponse response) { + String userEmail = extractEmail(); + User user = + userRepository.findByEmail(userEmail) + .orElseThrow(() -> new ValidationException( + "User not found")); + RefreshToken refreshToken = + refreshTokenRepository.findByUserIdAndExpiresAtAfter( + user.getId(), Instant.now()).orElseThrow( + () -> new ValidationException( + "Refresh token not found")); + expireRefreshToken(refreshToken); + Cookie cookie = new Cookie("refreshToken", null); cookie.setPath(REFRESH_TOKEN_COOKIE_PATH); response.addCookie(cookie); } + private void expireRefreshToken(final RefreshToken token) { + token.setExpiresAt(Instant.now()); + refreshTokenRepository.save(token); + } + private SecretKey getSignInKey() { byte[] keyBytes = Decoders.BASE64.decode(this.secret); return Keys.hmacShaKeyFor(keyBytes); diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index be2b6ed..e7e6d89 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -8,6 +8,11 @@ logging.file.name=./logs/app.log logging.level.root=info logging.level.com.podzilla.auth=debug +spring.cache.type=redis + +spring.data.redis.host=localhost +spring.data.redis.port=6379 + spring.datasource.url=jdbc:postgresql://localhost:5432/authDB spring.datasource.username=postgres spring.datasource.password=1234