diff --git a/src/main/java/Gotcha/common/config/CsrfConfig.java b/src/main/java/Gotcha/common/config/CsrfConfig.java new file mode 100644 index 00000000..3dc6ded6 --- /dev/null +++ b/src/main/java/Gotcha/common/config/CsrfConfig.java @@ -0,0 +1,33 @@ +package Gotcha.common.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.web.csrf.CookieCsrfTokenRepository; +import org.springframework.security.web.csrf.CsrfTokenRequestAttributeHandler; + +@Configuration +public class CsrfConfig { + + @Value("${csrf.cookie.secure}") + private boolean secure; + + @Bean + public CookieCsrfTokenRepository csrfTokenRepository() { + CookieCsrfTokenRepository repository = CookieCsrfTokenRepository.withHttpOnlyFalse(); + + repository.setCookieName("XSRF-TOKEN"); + repository.setCookiePath("/"); + repository.setCookieHttpOnly(false); + repository.setSecure(secure); + + return repository; + } + + @Bean + public CsrfTokenRequestAttributeHandler csrfTokenRequestAttributeHandler() { + CsrfTokenRequestAttributeHandler handler = new CsrfTokenRequestAttributeHandler(); + handler.setCsrfRequestAttributeName(null); + return handler; + } +} \ No newline at end of file diff --git a/src/main/java/Gotcha/common/config/SecurityConfig.java b/src/main/java/Gotcha/common/config/SecurityConfig.java index 9a40f2dd..2a04a739 100644 --- a/src/main/java/Gotcha/common/config/SecurityConfig.java +++ b/src/main/java/Gotcha/common/config/SecurityConfig.java @@ -1,13 +1,12 @@ package Gotcha.common.config; -import Gotcha.common.jwt.exception.JwtExceptionCode; +import Gotcha.common.exception.CustomAccessDeniedHandler; import Gotcha.common.jwt.filter.JwtAuthenticationFilter; import Gotcha.common.jwt.filter.JwtExceptionFilter; import Gotcha.domain.user.entity.Role; import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.security.access.AccessDeniedException; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; @@ -16,6 +15,8 @@ import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +import org.springframework.security.web.csrf.CookieCsrfTokenRepository; +import org.springframework.security.web.csrf.CsrfTokenRequestAttributeHandler; import org.springframework.web.cors.CorsConfigurationSource; import static Gotcha.common.constants.SecurityConstants.ADMIN_ENDPOINTS; @@ -28,6 +29,9 @@ public class SecurityConfig { private final JwtAuthenticationFilter jwtAuthenticationFilter; private final JwtExceptionFilter jwtExceptionFilter; private final CorsConfigurationSource corsConfigurationSource; + private final CookieCsrfTokenRepository csrfTokenRepository; + private final CsrfTokenRequestAttributeHandler csrfTokenRequestAttributeHandler; + private final CustomAccessDeniedHandler accessDeniedHandler; @Bean PasswordEncoder passwordEncoder() { @@ -38,7 +42,13 @@ PasswordEncoder passwordEncoder() { public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http - .csrf(AbstractHttpConfigurer::disable) + .csrf(csrf -> csrf + .requireCsrfProtectionMatcher(request -> { + String path = request.getRequestURI(); + return path.equals("/api/v1/auth/token-reissue"); + }) + .csrfTokenRepository(csrfTokenRepository) + .csrfTokenRequestHandler(csrfTokenRequestAttributeHandler)) .cors((cors) -> cors.configurationSource(corsConfigurationSource)) .formLogin(AbstractHttpConfigurer::disable) .httpBasic(AbstractHttpConfigurer::disable) @@ -49,10 +59,8 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti .requestMatchers(PUBLIC_ENDPOINTS).permitAll() .requestMatchers(ADMIN_ENDPOINTS).hasAnyRole(String.valueOf(Role.ADMIN)) .anyRequest().authenticated() - ).exceptionHandling(exception -> exception - .accessDeniedHandler((request, response, accessDeniedException) -> { - throw new AccessDeniedException(JwtExceptionCode.ACCESS_DENIED.getMessage()); - })) + ).exceptionHandling(exception -> + exception.accessDeniedHandler(accessDeniedHandler)) .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class) .addFilterBefore(jwtExceptionFilter, JwtAuthenticationFilter.class); diff --git a/src/main/java/Gotcha/common/exception/CustomAccessDeniedHandler.java b/src/main/java/Gotcha/common/exception/CustomAccessDeniedHandler.java new file mode 100644 index 00000000..d6e75b98 --- /dev/null +++ b/src/main/java/Gotcha/common/exception/CustomAccessDeniedHandler.java @@ -0,0 +1,44 @@ +package Gotcha.common.exception; + +import Gotcha.common.exception.exceptionCode.ExceptionCode; +import Gotcha.common.exception.exceptionCode.GlobalExceptionCode; +import Gotcha.common.jwt.exception.JwtExceptionCode; +import com.fasterxml.jackson.databind.ObjectMapper; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.web.access.AccessDeniedHandler; +import org.springframework.security.web.csrf.InvalidCsrfTokenException; +import org.springframework.security.web.csrf.MissingCsrfTokenException; +import org.springframework.stereotype.Component; + +import java.io.IOException; + +@Component +@RequiredArgsConstructor +@Slf4j +public class CustomAccessDeniedHandler implements AccessDeniedHandler { + private final ObjectMapper objectMapper; + + @Override + public void handle(HttpServletRequest request, + HttpServletResponse response, + AccessDeniedException accessDeniedException) throws IOException { + + log.warn("[AccessDeniedException] {} occurred", accessDeniedException.getClass().getSimpleName()); + + ExceptionCode exceptionCode; + if (accessDeniedException instanceof InvalidCsrfTokenException || + accessDeniedException instanceof MissingCsrfTokenException) { + exceptionCode = GlobalExceptionCode.CSRF_INVALID; + } else { + exceptionCode = JwtExceptionCode.ACCESS_DENIED; + } + + response.setStatus(exceptionCode.getStatus().value()); + response.setContentType("application/json;charset=UTF-8"); + objectMapper.writeValue(response.getWriter(), ExceptionRes.from(exceptionCode)); + } +} \ No newline at end of file diff --git a/src/main/java/Gotcha/common/exception/exceptionCode/GlobalExceptionCode.java b/src/main/java/Gotcha/common/exception/exceptionCode/GlobalExceptionCode.java index 383a8acc..9bed9b45 100644 --- a/src/main/java/Gotcha/common/exception/exceptionCode/GlobalExceptionCode.java +++ b/src/main/java/Gotcha/common/exception/exceptionCode/GlobalExceptionCode.java @@ -7,7 +7,8 @@ public enum GlobalExceptionCode implements ExceptionCode { INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "서버 에러입니다. 서버 팀에 연락주세요."), - FIELD_VALIDATION_ERROR(HttpStatus.BAD_REQUEST, "필드 검증 오류입니다."),; + FIELD_VALIDATION_ERROR(HttpStatus.BAD_REQUEST, "필드 검증 오류입니다."), + CSRF_INVALID(HttpStatus.FORBIDDEN, "CSRF 토큰이 올바르지 않습니다."); private final HttpStatus status; private final String message; diff --git a/src/main/java/Gotcha/common/jwt/filter/JwtExceptionFilter.java b/src/main/java/Gotcha/common/jwt/filter/JwtExceptionFilter.java index 341114f2..59b41359 100644 --- a/src/main/java/Gotcha/common/jwt/filter/JwtExceptionFilter.java +++ b/src/main/java/Gotcha/common/jwt/filter/JwtExceptionFilter.java @@ -14,7 +14,6 @@ import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.security.access.AccessDeniedException; import org.springframework.security.authentication.AuthenticationServiceException; import org.springframework.web.filter.OncePerRequestFilter; @@ -40,8 +39,6 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse handleTokenException(response, JwtExceptionCode.UNKNOWN_TOKEN_ERROR, HttpServletResponse.SC_UNAUTHORIZED); } catch (AuthenticationServiceException e){ handleTokenException(response, JwtExceptionCode.ACCESS_TOKEN_NOT_FOUND, HttpServletResponse.SC_UNAUTHORIZED); - } catch (AccessDeniedException e){ - handleTokenException(response, JwtExceptionCode.ACCESS_DENIED, HttpServletResponse.SC_FORBIDDEN); } } diff --git a/src/main/java/Gotcha/common/jwt/token/JwtHelper.java b/src/main/java/Gotcha/common/jwt/token/JwtHelper.java index 3a8052ea..bf77b5c7 100644 --- a/src/main/java/Gotcha/common/jwt/token/JwtHelper.java +++ b/src/main/java/Gotcha/common/jwt/token/JwtHelper.java @@ -23,29 +23,29 @@ public class JwtHelper { private final RefreshTokenService refreshTokenService; private final BlackListTokenService blackListTokenService; - public TokenDto createToken(User user) { + public TokenDto createToken(User user, boolean autoSignIn) { Long userId = user.getId(); String email = user.getEmail(); - return getTokenDto(user, userId, email); + return getTokenDto(user, userId, email, autoSignIn); } public TokenDto createGuestToken(User guest){ Long userId = guest.getId(); String username = guest.getNickname(); - return getTokenDto(guest, userId, username); + return getTokenDto(guest, userId, username, false); } - private TokenDto getTokenDto(User user, Long userId, String username) { + private TokenDto getTokenDto(User user, Long userId, String username, boolean autoSignIn) { String role = String.valueOf(user.getRole()); String accessToken = TOKEN_PREFIX + tokenProvider.createAccessToken(role, userId, username); - String refreshToken = tokenProvider.createRefreshToken(role, userId, username); + String refreshToken = tokenProvider.createRefreshToken(role, userId, username, autoSignIn); LocalDateTime accessTokenExpiredAt = tokenProvider.getExpiryDate( accessToken.replace(TOKEN_PREFIX, "").trim() ); refreshTokenService.saveRefreshToken(username, refreshToken); - return new TokenDto(accessToken, refreshToken, accessTokenExpiredAt); + return new TokenDto(accessToken, refreshToken, accessTokenExpiredAt, autoSignIn); } public TokenDto reissueToken(String refreshToken) { @@ -59,8 +59,10 @@ public TokenDto reissueToken(String refreshToken) { Long userId = tokenProvider.getUserId(refreshToken); String role = tokenProvider.getRole(refreshToken); + boolean autoSignIn = tokenProvider.isAutoSignIn(refreshToken); + String newAccessToken = TOKEN_PREFIX + tokenProvider.createAccessToken(role, userId, username); - String newRefreshToken = tokenProvider.createRefreshToken(role, userId, username); + String newRefreshToken = tokenProvider.createRefreshToken(role, userId, username, autoSignIn); LocalDateTime newAccessTokenExpiredAt = tokenProvider.getExpiryDate( newAccessToken.replace(TOKEN_PREFIX, "").trim() ); @@ -68,7 +70,7 @@ public TokenDto reissueToken(String refreshToken) { refreshTokenService.deleteRefreshToken(refreshToken); refreshTokenService.saveRefreshToken(username, newRefreshToken); - return new TokenDto(newAccessToken, newRefreshToken, newAccessTokenExpiredAt); + return new TokenDto(newAccessToken, newRefreshToken, newAccessTokenExpiredAt, autoSignIn); } public void removeToken(String accessToken, String refreshToken, HttpServletResponse response) { diff --git a/src/main/java/Gotcha/common/jwt/token/TokenProvider.java b/src/main/java/Gotcha/common/jwt/token/TokenProvider.java index d7dba9db..e3336958 100644 --- a/src/main/java/Gotcha/common/jwt/token/TokenProvider.java +++ b/src/main/java/Gotcha/common/jwt/token/TokenProvider.java @@ -19,33 +19,44 @@ public class TokenProvider { private final SecretKey secretKey; private final long accessExpiration; private final long refreshExpiration; + private final long autoRefreshExpiration; private final String issuer; public TokenProvider(@Value("${jwt.secret-key}") String secret_key, @Value("${jwt.access-expiration}") long accessExpiration, @Value("${jwt.refresh-expiration}") long refreshExpiration, + @Value("${jwt.auto-login-refresh-expiration}") long autoRefreshExpiration, @Value("${jwt.issuer}") String issuer) { this.secretKey = new SecretKeySpec(secret_key.getBytes(StandardCharsets.UTF_8), Jwts.SIG.HS256.key().build().getAlgorithm()); this.accessExpiration = accessExpiration; this.refreshExpiration = refreshExpiration; + this.autoRefreshExpiration = autoRefreshExpiration; this.issuer = issuer; } public String createAccessToken(String role, Long userId, String username) { - return createToken(makeClaims(role, userId), username, accessExpiration); + return createToken(makeAccessTokenClaims(role, userId), username, accessExpiration); } - public String createRefreshToken(String role, Long userId, String username) { - return createToken(makeClaims(role, userId), username, refreshExpiration); + public String createRefreshToken(String role, Long userId, String username, boolean autoSignIn) { + return createToken(makeRefreshTokenClaims(role, userId, autoSignIn), username, autoSignIn?autoRefreshExpiration:refreshExpiration); } - private Map makeClaims(String role, Long userId) { + private Map makeAccessTokenClaims(String role, Long userId) { Map claims = new HashMap<>(); claims.put("role", role); claims.put("userId", userId); return claims; } + private Map makeRefreshTokenClaims(String role, Long userId, boolean autoSignIn) { + Map claims = new HashMap<>(); + claims.put("role", role); + claims.put("userId", userId); + claims.put("auto", autoSignIn); + return claims; + } + private String createToken(Map claims, String subject, Long expiry) { return Jwts.builder() .header() @@ -68,6 +79,12 @@ private Claims getClaims(String token) { .getPayload(); } + public boolean isAutoSignIn(String token) { + Claims claims = getClaims(token); + Boolean auto = claims.get("auto", Boolean.class); + return Boolean.TRUE.equals(auto); + } + public String getUsername(String token) { return getClaims(token).getSubject(); } diff --git a/src/main/java/Gotcha/common/util/CookieUtil.java b/src/main/java/Gotcha/common/util/CookieUtil.java index 7c562fd9..16588e6a 100644 --- a/src/main/java/Gotcha/common/util/CookieUtil.java +++ b/src/main/java/Gotcha/common/util/CookieUtil.java @@ -11,15 +11,21 @@ public class CookieUtil { @Value("${token.refresh.in-cookie}") private long COOKIE_REFRESH_EXPIRATION; - public ResponseCookie createCookie(String key, String value) { + @Value("${csrf.cookie.secure}") + private boolean secure; - return ResponseCookie.from(key, value) + public ResponseCookie createCookie(String key, String value, boolean autoSignIn) { + + ResponseCookie.ResponseCookieBuilder cookie = ResponseCookie.from(key, value) .path("/") .httpOnly(true) - .maxAge(COOKIE_REFRESH_EXPIRATION) - .secure(true) - .sameSite("None") - .build(); + .secure(secure) + .sameSite("None"); + + if(autoSignIn) + cookie.maxAge(COOKIE_REFRESH_EXPIRATION); + + return cookie.build(); } public void deleteCookie(String cookieName, HttpServletResponse response) { @@ -28,7 +34,7 @@ public void deleteCookie(String cookieName, HttpServletResponse response) { .path("/") .httpOnly(true) .maxAge(0) - .secure(true) + .secure(secure) .sameSite("None") .build(); diff --git a/src/main/java/Gotcha/domain/auth/controller/AuthController.java b/src/main/java/Gotcha/domain/auth/controller/AuthController.java index eebf772c..a66f84f2 100644 --- a/src/main/java/Gotcha/domain/auth/controller/AuthController.java +++ b/src/main/java/Gotcha/domain/auth/controller/AuthController.java @@ -13,11 +13,14 @@ import Gotcha.domain.auth.dto.TokenDto; import Gotcha.domain.auth.service.AuthService; import Gotcha.domain.user.service.UserService; +import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpHeaders; import org.springframework.http.ResponseEntity; +import org.springframework.security.web.csrf.CookieCsrfTokenRepository; +import org.springframework.security.web.csrf.CsrfToken; import org.springframework.web.bind.annotation.CookieValue; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; @@ -40,26 +43,28 @@ public class AuthController implements AuthApi { private final CookieUtil cookieUtil; private final MailCodeService mailCodeService; private final UserService userService; + private final CookieCsrfTokenRepository csrfTokenRepository; + @PostMapping("/sign-up") public ResponseEntity signUp(@Valid @RequestBody SignUpReq signUpReq) { TokenDto tokenDto = authService.signUp(signUpReq); - return createTokenRes(tokenDto); + return createTokenRes(tokenDto, tokenDto.autoSignIn()); } @PostMapping("/sign-in") public ResponseEntity signIn(@Valid @RequestBody SignInReq signInReq) { TokenDto tokenDto = authService.signIn(signInReq); - return createTokenRes(tokenDto); + return createTokenRes(tokenDto, signInReq.autoSignIn()); } @PostMapping("/guest/sign-in") public ResponseEntity guestSignIn(){ TokenDto tokenDto = authService.guestSignIn(); - return createTokenRes(tokenDto); + return createTokenRes(tokenDto, tokenDto.autoSignIn()); } @PostMapping("/token-reissue") @@ -69,7 +74,7 @@ public ResponseEntity reIssueToken(@CookieValue(name = REFRESH_COOKIE_VALUE, } TokenDto tokenDto = authService.reissueAccessToken(refreshToken); - return createTokenRes(tokenDto); + return createTokenRes(tokenDto, tokenDto.autoSignIn()); } @PostMapping("/email/send") @@ -97,7 +102,14 @@ public ResponseEntity signOut(@RequestHeader(value = ACCESS_HEADER_VALUE, req return ResponseEntity.ok(SuccessRes.from("로그아웃 되었습니다.")); } - private ResponseEntity createTokenRes(TokenDto tokenDto) { + @GetMapping("/csrf-token") + public ResponseEntity getCsrfToken(HttpServletRequest request, HttpServletResponse response) { + CsrfToken token = csrfTokenRepository.generateToken(request); + csrfTokenRepository.saveToken(token, request, response); + return ResponseEntity.ok().build(); + } + + private ResponseEntity createTokenRes(TokenDto tokenDto, boolean autoSignIn) { Map responseData = new HashMap<>(); responseData.put("accessToken", tokenDto.accessToken()); responseData.put("expiredAt", tokenDto.accessTokenExpiredAt()); @@ -105,7 +117,7 @@ private ResponseEntity createTokenRes(TokenDto tokenDto) { return ResponseEntity.ok() .header(HttpHeaders.SET_COOKIE, cookieUtil.createCookie(REFRESH_COOKIE_VALUE, - tokenDto.refreshToken()).toString()) + tokenDto.refreshToken(), autoSignIn).toString()) .body(responseData); } } diff --git a/src/main/java/Gotcha/domain/auth/dto/SignInReq.java b/src/main/java/Gotcha/domain/auth/dto/SignInReq.java index c9dd98fe..c920dfef 100644 --- a/src/main/java/Gotcha/domain/auth/dto/SignInReq.java +++ b/src/main/java/Gotcha/domain/auth/dto/SignInReq.java @@ -12,6 +12,9 @@ public record SignInReq( @Schema(description = "비밀번호", example = "password123@") @NotBlank(message = "비밀번호를 입력해주세요.") - String password + String password, + + @Schema(description = "자동 로그인 유무", example = "true") + boolean autoSignIn ) { } diff --git a/src/main/java/Gotcha/domain/auth/dto/TokenDto.java b/src/main/java/Gotcha/domain/auth/dto/TokenDto.java index 75548eb6..e118bc73 100644 --- a/src/main/java/Gotcha/domain/auth/dto/TokenDto.java +++ b/src/main/java/Gotcha/domain/auth/dto/TokenDto.java @@ -5,9 +5,13 @@ public record TokenDto( String accessToken, String refreshToken, - LocalDateTime accessTokenExpiredAt + LocalDateTime accessTokenExpiredAt, + boolean autoSignIn ) { public static TokenDto of(String accessToken, String refreshToken, LocalDateTime accessTokenExpiredAt) { - return new TokenDto(accessToken, refreshToken, accessTokenExpiredAt); + return new TokenDto(accessToken, refreshToken, accessTokenExpiredAt, false); + } + public static TokenDto of(String accessToken, String refreshToken, LocalDateTime accessTokenExpiredAt, boolean autoSignIn) { + return new TokenDto(accessToken, refreshToken, accessTokenExpiredAt, autoSignIn); } } \ No newline at end of file diff --git a/src/main/java/Gotcha/domain/auth/service/AuthService.java b/src/main/java/Gotcha/domain/auth/service/AuthService.java index 66daf412..d1e22855 100644 --- a/src/main/java/Gotcha/domain/auth/service/AuthService.java +++ b/src/main/java/Gotcha/domain/auth/service/AuthService.java @@ -61,7 +61,7 @@ public TokenDto signUp(SignUpReq signUpReq) { String encodePassword = passwordEncoder.encode(signUpReq.password()); User createdUser = userRepository.save(signUpReq.toEntity(encodePassword)); - return jwtHelper.createToken(createdUser); + return jwtHelper.createToken(createdUser, false); } @Transactional(readOnly = true) @@ -73,7 +73,7 @@ public TokenDto signIn(SignInReq signInReq){ throw new CustomException(AuthExceptionCode.INVALID_USERNAME_AND_PASSWORD); } - return jwtHelper.createToken(user); + return jwtHelper.createToken(user, signInReq.autoSignIn()); } public void signOut(String HeaderAccessToken, String refreshToken, HttpServletResponse response){ diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml new file mode 100644 index 00000000..167c3628 --- /dev/null +++ b/src/main/resources/application-dev.yml @@ -0,0 +1,59 @@ +spring: + datasource: + driver-class-name: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://${DATABASE_HOST:localhost}:${DATABASE_PORT:3306}/${DATABASE_NAME:gotcha} + username: ${DATABASE_USER:root} + password: ${DATABASE_PASSWORD:password} + + jpa: + hibernate: + ddl-auto: update + naming: + physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl + show-sql: true + properties: + hibernate: + default_batch_fetch_size: 1000 + dialect: org.hibernate.dialect.MySQLDialect + + mail: + host: smtp.gmail.com + port: 587 + username: ${MAIL_USERNAME} + password: ${MAIL_PASSWORD} + properties: + mail: + smtp: + auth: true + timeout: 5000 + starttls: + enable: true + + data: + redis: + host: ${REDIS_HOST:localhost} + port: ${REDIS_PORT:6379} + password: ${REDIS_PASS:} + +jwt: + secret-key: ${JWT_KEY:gotchaSecretKey_mN8xG4zH2K9YtR7mN1BvLpZ5QwX3T6JpC2DfV5LqZ7YgR8K1N9BvM3X6T2D} + access-expiration: ${JWT_ACCESS_EXPIRATION:1800000} #30분 + refresh-expiration: ${JWT_REFRESH_EXPIRATION:86400000} #1일 + auto-login-refresh-expiration: ${JWT_AUTO_REFRESH_EXPIRATION:1209600000} #14일 + issuer: ${JWT_ISSUER:gotcha!} + +token: + refresh: + in-cookie: ${COOKIE_REFRESH_EXPIRATION:1209600} #14일 + in-redis: ${REDIS_REFRESH_EXPIRATION:1209600} #14일 + +cache: + ttl: ${CACHE_TTL:60} + +mail: + sender: Gotcha! + subject: "[Gotcha!] 이메일 인증을 완료해주세요." + +csrf: + cookie: + secure: false diff --git a/src/main/resources/application-prod.yml b/src/main/resources/application-prod.yml new file mode 100644 index 00000000..a27e80a6 --- /dev/null +++ b/src/main/resources/application-prod.yml @@ -0,0 +1,59 @@ +spring: + datasource: + driver-class-name: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://${DATABASE_HOST:localhost}:${DATABASE_PORT:3306}/${DATABASE_NAME:gotcha} + username: ${DATABASE_USER:root} + password: ${DATABASE_PASSWORD:password} + + jpa: + hibernate: + ddl-auto: update + naming: + physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl + show-sql: true + properties: + hibernate: + default_batch_fetch_size: 1000 + dialect: org.hibernate.dialect.MySQLDialect + + mail: + host: smtp.gmail.com + port: 587 + username: ${MAIL_USERNAME} + password: ${MAIL_PASSWORD} + properties: + mail: + smtp: + auth: true + timeout: 5000 + starttls: + enable: true + + data: + redis: + host: ${REDIS_HOST:localhost} + port: ${REDIS_PORT:6379} + password: ${REDIS_PASS:} + +jwt: + secret-key: ${JWT_KEY:gotchaSecretKey_mN8xG4zH2K9YtR7mN1BvLpZ5QwX3T6JpC2DfV5LqZ7YgR8K1N9BvM3X6T2D} + access-expiration: ${JWT_ACCESS_EXPIRATION:1800000} #30분 + refresh-expiration: ${JWT_REFRESH_EXPIRATION:86400000} #1일 + auto-login-refresh-expiration: ${JWT_AUTO_REFRESH_EXPIRATION:1209600000} #14일 + issuer: ${JWT_ISSUER:gotcha!} + +token: + refresh: + in-cookie: ${COOKIE_REFRESH_EXPIRATION:1209600} #14일 + in-redis: ${REDIS_REFRESH_EXPIRATION:1209600} #14일 + +cache: + ttl: ${CACHE_TTL:60} + +mail: + sender: Gotcha! + subject: "[Gotcha!] 이메일 인증을 완료해주세요." + +csrf: + cookie: + secure: true \ No newline at end of file diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index bd48b3aa..caf4dfcd 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1,54 +1,3 @@ spring: - datasource: - driver-class-name: com.mysql.cj.jdbc.Driver - url: jdbc:mysql://${DATABASE_HOST:localhost}:${DATABASE_PORT:3306}/${DATABASE_NAME:gotcha} - username: ${DATABASE_USER:root} - password: ${DATABASE_PASSWORD:password} - - jpa: - hibernate: - ddl-auto: update - naming: - physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl - show-sql: true - properties: - hibernate: - default_batch_fetch_size: 1000 - dialect: org.hibernate.dialect.MySQLDialect - - mail: - host: smtp.gmail.com - port: 587 - username: ${MAIL_USERNAME} - password: ${MAIL_PASSWORD} - properties: - mail: - smtp: - auth: true - timeout: 5000 - starttls: - enable: true - - data: - redis: - host: ${REDIS_HOST:localhost} - port: ${REDIS_PORT:6379} - password: ${REDIS_PASS:} - -jwt: - secret-key: ${JWT_KEY:gotchaSecretKey_mN8xG4zH2K9YtR7mN1BvLpZ5QwX3T6JpC2DfV5LqZ7YgR8K1N9BvM3X6T2D} - access-expiration: ${JWT_ACCESS_EXPIRATION:1800000} - refresh-expiration: ${JWT_REFRESH_EXPIRATION:86400000} - issuer: ${JWT_ISSUER:gotcha!} - -token: - refresh: - in-cookie: ${COOKIE_REFRESH_EXPIRATION:648000} - in-redis: ${REDIS_REFRESH_EXPIRATION:648000} - -cache: - ttl: ${CACHE_TTL:60} - -mail: - sender: Gotcha! - subject: "[Gotcha!] 이메일 인증을 완료해주세요." \ No newline at end of file + profiles: + active: dev \ No newline at end of file