diff --git a/mengduck/week4/umc10th-yongjae/build.gradle b/mengduck/week4/umc10th-yongjae/build.gradle index 8e0f7db..bc194f5 100644 --- a/mengduck/week4/umc10th-yongjae/build.gradle +++ b/mengduck/week4/umc10th-yongjae/build.gradle @@ -26,6 +26,11 @@ dependencies { implementation 'org.springdoc:springdoc-openapi-starter-webmvc-api:3.0.1' implementation 'org.springframework.boot:spring-boot-starter-security' + implementation 'io.jsonwebtoken:jjwt-api:0.12.3' + implementation 'io.jsonwebtoken:jjwt-impl:0.12.3' + implementation 'io.jsonwebtoken:jjwt-jackson:0.12.3' + implementation 'org.springframework.boot:spring-boot-configuration-processor' + runtimeOnly 'com.mysql:mysql-connector-j' testImplementation 'org.springframework.boot:spring-boot-starter-test' diff --git a/mengduck/week4/umc10th-yongjae/src/main/java/org/example/umc10thyongjae/domain/auth/controller/AuthController.java b/mengduck/week4/umc10th-yongjae/src/main/java/org/example/umc10thyongjae/domain/auth/controller/AuthController.java index c51e0b5..75f727d 100644 --- a/mengduck/week4/umc10th-yongjae/src/main/java/org/example/umc10thyongjae/domain/auth/controller/AuthController.java +++ b/mengduck/week4/umc10th-yongjae/src/main/java/org/example/umc10thyongjae/domain/auth/controller/AuthController.java @@ -2,12 +2,16 @@ import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; +import org.example.umc10thyongjae.domain.auth.dto.request.LoginRequestDto; import org.example.umc10thyongjae.domain.auth.dto.request.SignUpRequestDto; +import org.example.umc10thyongjae.domain.auth.dto.response.LoginResponseDto; import org.example.umc10thyongjae.domain.auth.dto.response.SignUpResponseDto; import org.example.umc10thyongjae.domain.auth.dto.response.UserInfoResponseDto; import org.example.umc10thyongjae.domain.auth.service.AuthService; import org.example.umc10thyongjae.global.apiPayload.ApiResponse; import org.example.umc10thyongjae.global.apiPayload.code.GeneralSuccessCode; +import org.example.umc10thyongjae.global.security.entity.AuthUser; +import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.*; @RestController @@ -17,18 +21,28 @@ public class AuthController { private final AuthService authService; @PostMapping("/signUp") - public ApiResponse signUp( + public ApiResponse signUp( @RequestBody @Valid SignUpRequestDto dto ) { Long userId = authService.signUp(dto); - return ApiResponse.onSuccess(GeneralSuccessCode.OK, new SignUpResponseDto(userId)); + return ApiResponse.onSuccess(GeneralSuccessCode.OK, null); + } + + @PostMapping("/login") + public ApiResponse login( + @RequestBody @Valid LoginRequestDto dto + ) { + LoginResponseDto result = authService.login(dto); + + return ApiResponse.onSuccess(GeneralSuccessCode.OK, result); } @GetMapping("/users/me") public ApiResponse retrieveUserInfo( - @RequestAttribute long userId - ) { + @AuthenticationPrincipal AuthUser authUser + ) { + long userId = authUser.getUser().getId(); UserInfoResponseDto result = authService.getUserInfo(userId); return ApiResponse.onSuccess(GeneralSuccessCode.OK, result); diff --git a/mengduck/week4/umc10th-yongjae/src/main/java/org/example/umc10thyongjae/domain/auth/dto/request/LoginRequestDto.java b/mengduck/week4/umc10th-yongjae/src/main/java/org/example/umc10thyongjae/domain/auth/dto/request/LoginRequestDto.java new file mode 100644 index 0000000..5f1c63e --- /dev/null +++ b/mengduck/week4/umc10th-yongjae/src/main/java/org/example/umc10thyongjae/domain/auth/dto/request/LoginRequestDto.java @@ -0,0 +1,12 @@ +package org.example.umc10thyongjae.domain.auth.dto.request; + +import jakarta.validation.constraints.NotBlank; + +public record LoginRequestDto( + @NotBlank(message = "아이디 입력은 필수입니다.") + String id, + + @NotBlank(message = "비밀번호 입력은 필수입니다.") + String pwd +) { +} diff --git a/mengduck/week4/umc10th-yongjae/src/main/java/org/example/umc10thyongjae/domain/auth/dto/response/LoginResponseDto.java b/mengduck/week4/umc10th-yongjae/src/main/java/org/example/umc10thyongjae/domain/auth/dto/response/LoginResponseDto.java new file mode 100644 index 0000000..47d4764 --- /dev/null +++ b/mengduck/week4/umc10th-yongjae/src/main/java/org/example/umc10thyongjae/domain/auth/dto/response/LoginResponseDto.java @@ -0,0 +1,6 @@ +package org.example.umc10thyongjae.domain.auth.dto.response; + +public record LoginResponseDto( + String accessToken +) { +} diff --git a/mengduck/week4/umc10th-yongjae/src/main/java/org/example/umc10thyongjae/domain/auth/exception/.gitkeep b/mengduck/week4/umc10th-yongjae/src/main/java/org/example/umc10thyongjae/domain/auth/exception/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/mengduck/week4/umc10th-yongjae/src/main/java/org/example/umc10thyongjae/domain/auth/exception/code/.gitkeep b/mengduck/week4/umc10th-yongjae/src/main/java/org/example/umc10thyongjae/domain/auth/exception/code/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/mengduck/week4/umc10th-yongjae/src/main/java/org/example/umc10thyongjae/domain/auth/service/AuthService.java b/mengduck/week4/umc10th-yongjae/src/main/java/org/example/umc10thyongjae/domain/auth/service/AuthService.java index a5d7543..b85a14c 100644 --- a/mengduck/week4/umc10th-yongjae/src/main/java/org/example/umc10thyongjae/domain/auth/service/AuthService.java +++ b/mengduck/week4/umc10th-yongjae/src/main/java/org/example/umc10thyongjae/domain/auth/service/AuthService.java @@ -1,7 +1,9 @@ package org.example.umc10thyongjae.domain.auth.service; import lombok.RequiredArgsConstructor; +import org.example.umc10thyongjae.domain.auth.dto.request.LoginRequestDto; import org.example.umc10thyongjae.domain.auth.dto.request.SignUpRequestDto; +import org.example.umc10thyongjae.domain.auth.dto.response.LoginResponseDto; import org.example.umc10thyongjae.domain.auth.dto.response.UserInfoResponseDto; import org.example.umc10thyongjae.domain.auth.entity.FoodPreference; import org.example.umc10thyongjae.domain.auth.entity.Term; @@ -15,7 +17,10 @@ import org.example.umc10thyongjae.domain.auth.repository.UserRepository; import org.example.umc10thyongjae.domain.auth.repository.UserTermRepository; import org.example.umc10thyongjae.global.apiPayload.exception.AlreadyRegisterUserException; +import org.example.umc10thyongjae.global.apiPayload.exception.LoginUnavailableException; import org.example.umc10thyongjae.global.apiPayload.exception.NotDataFoundException; +import org.example.umc10thyongjae.global.security.entity.AuthUser; +import org.example.umc10thyongjae.global.security.util.JwtUtil; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -35,6 +40,7 @@ public class AuthService { private final FoodPreferenceRepository foodPreferenceRepository; private final UserFoodPreferenceRepository userFoodPreferenceRepository; private final PasswordEncoder passwordEncoder; + private final JwtUtil jwtUtil; @Transactional public Long signUp(SignUpRequestDto dto) { @@ -63,6 +69,20 @@ public Long signUp(SignUpRequestDto dto) { return user.getId(); } + @Transactional(readOnly = true) + public LoginResponseDto login(LoginRequestDto dto) { + User user = authRepository.findByLoginId(dto.id()) + .orElseThrow(LoginUnavailableException::new); + + if (!passwordEncoder.matches(dto.pwd(), user.getPwd())) { + throw new LoginUnavailableException(); + } + + String accessToken = jwtUtil.createAccessToken(new AuthUser(user)); + + return new LoginResponseDto(accessToken); + } + @Transactional(readOnly = true) public UserInfoResponseDto getUserInfo(long userId) { User entity = authRepository.findById(userId).orElseThrow( diff --git a/mengduck/week4/umc10th-yongjae/src/main/java/org/example/umc10thyongjae/domain/mission/exception/.gitkeep b/mengduck/week4/umc10th-yongjae/src/main/java/org/example/umc10thyongjae/domain/mission/exception/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/mengduck/week4/umc10th-yongjae/src/main/java/org/example/umc10thyongjae/domain/mission/exception/code/.gitkeep b/mengduck/week4/umc10th-yongjae/src/main/java/org/example/umc10thyongjae/domain/mission/exception/code/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/mengduck/week4/umc10th-yongjae/src/main/java/org/example/umc10thyongjae/domain/store/exception/.gitkeep b/mengduck/week4/umc10th-yongjae/src/main/java/org/example/umc10thyongjae/domain/store/exception/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/mengduck/week4/umc10th-yongjae/src/main/java/org/example/umc10thyongjae/domain/store/exception/code/.gitkeep b/mengduck/week4/umc10th-yongjae/src/main/java/org/example/umc10thyongjae/domain/store/exception/code/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/mengduck/week4/umc10th-yongjae/src/main/java/org/example/umc10thyongjae/global/apiPayload/code/GeneralErrorCode.java b/mengduck/week4/umc10th-yongjae/src/main/java/org/example/umc10thyongjae/global/apiPayload/code/GeneralErrorCode.java index 1fe6245..460cd27 100644 --- a/mengduck/week4/umc10th-yongjae/src/main/java/org/example/umc10thyongjae/global/apiPayload/code/GeneralErrorCode.java +++ b/mengduck/week4/umc10th-yongjae/src/main/java/org/example/umc10thyongjae/global/apiPayload/code/GeneralErrorCode.java @@ -9,6 +9,7 @@ public enum GeneralErrorCode implements BaseErrorCode { BAD_REQUEST(HttpStatus.BAD_REQUEST, "BAD_REQUEST", "잘못된 요청입니다. "), UNAUTHORIZED(HttpStatus.UNAUTHORIZED, "UNAUTHORIZED", "인증되지 않았습니다."), + LOGIN_UNAVAILABLE(HttpStatus.UNAUTHORIZED, "LOGIN_UNAVAILABLE", "아이디 또는 비밀번호가 일치하지 않습니다."), FORBIDDEN(HttpStatus.FORBIDDEN, "FORBIDDEN", "접근이 금지되었습니다."), NOT_FOUND(HttpStatus.NOT_FOUND, "NOT_FOUND", "해당 리소스를 찾을 수 없습니다."), ALREADY_REGISTER_USER(HttpStatus.CONFLICT, "ALREADY_REGISTER_USER", "이미 가입된 사용자입니다."), diff --git a/mengduck/week4/umc10th-yongjae/src/main/java/org/example/umc10thyongjae/global/apiPayload/exception/LoginUnavailableException.java b/mengduck/week4/umc10th-yongjae/src/main/java/org/example/umc10thyongjae/global/apiPayload/exception/LoginUnavailableException.java new file mode 100644 index 0000000..d9d0124 --- /dev/null +++ b/mengduck/week4/umc10th-yongjae/src/main/java/org/example/umc10thyongjae/global/apiPayload/exception/LoginUnavailableException.java @@ -0,0 +1,10 @@ +package org.example.umc10thyongjae.global.apiPayload.exception; + +import org.example.umc10thyongjae.global.apiPayload.code.GeneralErrorCode; + +public class LoginUnavailableException extends CommonException { + + public LoginUnavailableException() { + super(GeneralErrorCode.LOGIN_UNAVAILABLE); + } +} diff --git a/mengduck/week4/umc10th-yongjae/src/main/java/org/example/umc10thyongjae/global/apiPayload/handler/HeaderAuthInterceptor.java b/mengduck/week4/umc10th-yongjae/src/main/java/org/example/umc10thyongjae/global/apiPayload/handler/HeaderAuthInterceptor.java index 989d8cc..277d8fa 100644 --- a/mengduck/week4/umc10th-yongjae/src/main/java/org/example/umc10thyongjae/global/apiPayload/handler/HeaderAuthInterceptor.java +++ b/mengduck/week4/umc10th-yongjae/src/main/java/org/example/umc10thyongjae/global/apiPayload/handler/HeaderAuthInterceptor.java @@ -4,6 +4,8 @@ import jakarta.servlet.http.HttpServletResponse; import org.springframework.web.servlet.HandlerInterceptor; +//TODO- @AuthenticationPrincipal AuthUser authUser로 전체 대체 후 제거 +@Deprecated public class HeaderAuthInterceptor implements HandlerInterceptor { @Override diff --git a/mengduck/week4/umc10th-yongjae/src/main/java/org/example/umc10thyongjae/global/config/SecurityConfig.java b/mengduck/week4/umc10th-yongjae/src/main/java/org/example/umc10thyongjae/global/config/SecurityConfig.java index a160554..38c3c27 100644 --- a/mengduck/week4/umc10th-yongjae/src/main/java/org/example/umc10thyongjae/global/config/SecurityConfig.java +++ b/mengduck/week4/umc10th-yongjae/src/main/java/org/example/umc10thyongjae/global/config/SecurityConfig.java @@ -1,7 +1,11 @@ package org.example.umc10thyongjae.global.config; +import lombok.RequiredArgsConstructor; +import org.example.umc10thyongjae.domain.auth.service.CustomUserDetailsService; import org.example.umc10thyongjae.global.apiPayload.handler.CustomAccessDenied; import org.example.umc10thyongjae.global.apiPayload.handler.CustomEntryPoint; +import org.example.umc10thyongjae.global.security.filter.JwtAuthFilter; +import org.example.umc10thyongjae.global.security.util.JwtUtil; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; @@ -9,18 +13,24 @@ import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.util.matcher.MediaTypeRequestMatcher; import org.springframework.security.web.SecurityFilterChain; import org.springframework.web.accept.HeaderContentNegotiationStrategy; @EnableWebSecurity @Configuration +@RequiredArgsConstructor public class SecurityConfig { + private final JwtUtil jwtUtil; + private final CustomUserDetailsService customUserDetailsService; + private final String[] allowUris = { "/swagger-ui/**", "/swagger-resources/**", "/v3/api-docs/**", "/auth/signUp", + "/auth/login", "/login" }; @@ -42,12 +52,9 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti ) .accessDeniedHandler(customAccessDenied()) ) - .formLogin(form -> form - .usernameParameter("id") - .passwordParameter("pwd") - .defaultSuccessUrl("/swagger-ui/index.html", true) - .permitAll() - ) + .addFilterBefore(jwtAuthFilter(), UsernamePasswordAuthenticationFilter.class) + .formLogin(AbstractHttpConfigurer::disable) + .sessionManagement(AbstractHttpConfigurer::disable) .logout(logout -> logout .logoutUrl("/logout") .logoutSuccessUrl("/login?logout") @@ -71,4 +78,9 @@ public CustomAccessDenied customAccessDenied() { public CustomEntryPoint customEntryPoint() { return new CustomEntryPoint(); } + + @Bean + public JwtAuthFilter jwtAuthFilter() { + return new JwtAuthFilter(jwtUtil, customUserDetailsService); + } } diff --git a/mengduck/week4/umc10th-yongjae/src/main/java/org/example/umc10thyongjae/global/config/WebConfig.java b/mengduck/week4/umc10th-yongjae/src/main/java/org/example/umc10thyongjae/global/config/WebConfig.java index abc5b87..efde314 100644 --- a/mengduck/week4/umc10th-yongjae/src/main/java/org/example/umc10thyongjae/global/config/WebConfig.java +++ b/mengduck/week4/umc10th-yongjae/src/main/java/org/example/umc10thyongjae/global/config/WebConfig.java @@ -14,6 +14,7 @@ public void addInterceptors(InterceptorRegistry registry) { .addPathPatterns("/**") .excludePathPatterns( "/auth/signUp", + "/auth/login", "/swagger-ui/**", "/swagger-resources/**", "/v3/api-docs/**" diff --git a/mengduck/week4/umc10th-yongjae/src/main/java/org/example/umc10thyongjae/global/security/entity/AuthUser.java b/mengduck/week4/umc10th-yongjae/src/main/java/org/example/umc10thyongjae/global/security/entity/AuthUser.java new file mode 100644 index 0000000..6178e36 --- /dev/null +++ b/mengduck/week4/umc10th-yongjae/src/main/java/org/example/umc10thyongjae/global/security/entity/AuthUser.java @@ -0,0 +1,32 @@ +package org.example.umc10thyongjae.global.security.entity; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.example.umc10thyongjae.domain.auth.entity.User; +import org.jspecify.annotations.Nullable; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; + +import java.util.Collection; +import java.util.List; + +@Getter +@RequiredArgsConstructor +public class AuthUser implements UserDetails { + private final User user; + + @Override + public Collection getAuthorities() { + return List.of(); + } + + @Override + public @Nullable String getPassword() { + return user.getPwd(); + } + + @Override + public String getUsername() { + return user.getLoginId(); + } +} diff --git a/mengduck/week4/umc10th-yongjae/src/main/java/org/example/umc10thyongjae/global/security/filter/JwtAuthFilter.java b/mengduck/week4/umc10th-yongjae/src/main/java/org/example/umc10thyongjae/global/security/filter/JwtAuthFilter.java new file mode 100644 index 0000000..78379b4 --- /dev/null +++ b/mengduck/week4/umc10th-yongjae/src/main/java/org/example/umc10thyongjae/global/security/filter/JwtAuthFilter.java @@ -0,0 +1,73 @@ +package org.example.umc10thyongjae.global.security.filter; + +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import org.example.umc10thyongjae.domain.auth.service.CustomUserDetailsService; +import org.example.umc10thyongjae.global.apiPayload.ApiResponse; +import org.example.umc10thyongjae.global.apiPayload.code.BaseErrorCode; +import org.example.umc10thyongjae.global.apiPayload.code.GeneralErrorCode; +import org.example.umc10thyongjae.global.security.util.JwtUtil; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.web.filter.OncePerRequestFilter; +import tools.jackson.databind.ObjectMapper; + +import java.io.IOException; + +@RequiredArgsConstructor +public class JwtAuthFilter extends OncePerRequestFilter { + + private final JwtUtil jwtUtil; + private final CustomUserDetailsService customUserDetailsService; + + @Override + protected void doFilterInternal( + @NonNull HttpServletRequest request, + @NonNull HttpServletResponse response, + @NonNull FilterChain filterChain + ) throws ServletException, IOException { + + try { + // 토큰 가져오기 + String token = request.getHeader("Authorization"); + // token이 없거나 Bearer가 아니면 넘기기 + if (token == null || !token.startsWith("Bearer ")) { + filterChain.doFilter(request, response); + return; + } + // Bearer이면 추출 + token = token.replace("Bearer ", ""); + // AccessToken 검증하기: 올바른 토큰이면 + if (jwtUtil.isValid(token)) { + // 토큰에서 이메일 추출 + String email = jwtUtil.getEmail(token); + // 인증 객체 생성: 이메일로 찾아온 뒤, 인증 객체 생성 + UserDetails user = customUserDetailsService.loadUserByUsername(email); + Authentication auth = new UsernamePasswordAuthenticationToken( + user, + null, + user.getAuthorities() + ); + // 인증 완료 후 SecurityContextHolder에 넣기 + SecurityContextHolder.getContext().setAuthentication(auth); + } + filterChain.doFilter(request, response); + } catch (Exception e) { + ObjectMapper mapper = new ObjectMapper(); + BaseErrorCode code = GeneralErrorCode.UNAUTHORIZED; + + response.setContentType("application/json;charset=UTF-8"); + response.setStatus(code.getStatus().value()); + + ApiResponse errorResponse = ApiResponse.onFailure(code,null); + + mapper.writeValue(response.getOutputStream(), errorResponse); + } + } +} \ No newline at end of file diff --git a/mengduck/week4/umc10th-yongjae/src/main/java/org/example/umc10thyongjae/global/security/util/JwtUtil.java b/mengduck/week4/umc10th-yongjae/src/main/java/org/example/umc10thyongjae/global/security/util/JwtUtil.java new file mode 100644 index 0000000..ea99349 --- /dev/null +++ b/mengduck/week4/umc10th-yongjae/src/main/java/org/example/umc10thyongjae/global/security/util/JwtUtil.java @@ -0,0 +1,93 @@ +package org.example.umc10thyongjae.global.security.util; + +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jws; +import io.jsonwebtoken.JwtException; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.security.Keys; +import org.springframework.security.core.GrantedAuthority; +import org.example.umc10thyongjae.global.security.entity.AuthUser; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import javax.crypto.SecretKey; +import java.nio.charset.StandardCharsets; +import java.time.Duration; +import java.time.Instant; +import java.util.Date; +import java.util.stream.Collectors; + +@Component +public class JwtUtil { + + private final SecretKey secretKey; + private final Duration accessExpiration; + + public JwtUtil( + @Value("${jwt.token.secretKey}") String secret, + @Value("${jwt.token.expiration.access}") Long accessExpiration + ) { + this.secretKey = Keys.hmacShaKeyFor(secret.getBytes(StandardCharsets.UTF_8)); + this.accessExpiration = Duration.ofMillis(accessExpiration); + } + + // AccessToken 생성 + public String createAccessToken(AuthUser user) { + return createToken(user, accessExpiration); + } + + /** 토큰에서 이메일 가져오기 + * + * @param token 유저 정보를 추출할 토큰 + * @return 유저 이메일을 토큰에서 추출합니다 + */ + public String getEmail(String token) { + try { + return getClaims(token).getPayload().getSubject(); // Parsing해서 Subject 가져오기 + } catch (JwtException e) { + return null; + } + } + + /** 토큰 유효성 확인 + * + * @param token 유효한지 확인할 토큰 + * @return True, False 반환합니다 + */ + public boolean isValid(String token) { + try { + getClaims(token); + return true; + } catch (JwtException e) { + return false; + } + } + + // 토큰 생성 + private String createToken(AuthUser user, Duration expiration) { + Instant now = Instant.now(); + + // 인가 정보 + String authorities = user.getAuthorities().stream() + .map(GrantedAuthority::getAuthority) + .collect(Collectors.joining(",")); + + return Jwts.builder() + .subject(user.getUsername()) // User 이메일을 Subject로 + .claim("role", authorities) + .claim("email", user.getUsername()) + .issuedAt(Date.from(now)) // 언제 발급한지 + .expiration(Date.from(now.plus(expiration))) // 언제까지 유효한지 + .signWith(secretKey) // sign할 Key + .compact(); + } + + // 토큰 정보 가져오기 + private Jws getClaims(String token) throws JwtException { + return Jwts.parser() + .verifyWith(secretKey) + .clockSkewSeconds(60) + .build() + .parseSignedClaims(token); + } +} \ No newline at end of file diff --git a/mengduck/week4/umc10th-yongjae/src/main/resources/application.yml b/mengduck/week4/umc10th-yongjae/src/main/resources/application.yml index b8276bc..9752707 100644 --- a/mengduck/week4/umc10th-yongjae/src/main/resources/application.yml +++ b/mengduck/week4/umc10th-yongjae/src/main/resources/application.yml @@ -16,4 +16,9 @@ spring: ddl-auto: validate properties: hibernate: - format_sql: true \ No newline at end of file + format_sql: true +jwt: + token: + secretKey: ${JWT_SECRET_KEY} + expiration: + access: 1800000 \ No newline at end of file