diff --git a/src/main/java/com/ordertogether/team14_be/auth/application/service/AuthService.java b/src/main/java/com/ordertogether/team14_be/auth/application/service/AuthService.java index 0bca91c1..33b62570 100644 --- a/src/main/java/com/ordertogether/team14_be/auth/application/service/AuthService.java +++ b/src/main/java/com/ordertogether/team14_be/auth/application/service/AuthService.java @@ -1,6 +1,6 @@ package com.ordertogether.team14_be.auth.application.service; -import com.ordertogether.team14_be.auth.JwtUtil; +import com.ordertogether.team14_be.auth.persistence.JwtUtil; import com.ordertogether.team14_be.member.application.service.MemberService; import com.ordertogether.team14_be.member.persistence.entity.Member; import org.springframework.stereotype.Service; diff --git a/src/main/java/com/ordertogether/team14_be/auth/persistence/JwtInterceptor.java b/src/main/java/com/ordertogether/team14_be/auth/persistence/JwtInterceptor.java new file mode 100644 index 00000000..e6ce3ba1 --- /dev/null +++ b/src/main/java/com/ordertogether/team14_be/auth/persistence/JwtInterceptor.java @@ -0,0 +1,48 @@ +package com.ordertogether.team14_be.auth.persistence; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.ordertogether.team14_be.member.application.exception.NotFoundMember; +import com.ordertogether.team14_be.member.persistence.entity.Member; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.stereotype.Component; +import org.springframework.web.servlet.HandlerInterceptor; + +@RequiredArgsConstructor +@Slf4j +@Component +public class JwtInterceptor implements HandlerInterceptor { + private final JwtUtil jwtUtil; + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) + throws Exception { + if (HttpMethod.OPTIONS.matches(request.getMethod())) { + return true; + } + + String authorization = request.getHeader(HttpHeaders.AUTHORIZATION); + String token = authorization.replaceAll("Bearer ", ""); + + if (token != null && token.length() > 10) { + log.debug("토큰 상태:: " + token); + + if (jwtUtil.vaildToken(token)) { + ObjectMapper objectMapper = new ObjectMapper(); + + String member = objectMapper.writeValueAsString(jwtUtil.decodeJwt(token).get("member")); + Member accessMember = objectMapper.readValue(member, Member.class); + + request.setAttribute("member", accessMember); + return true; + } + } else { + throw new NotFoundMember(); + } + return false; + } +} diff --git a/src/main/java/com/ordertogether/team14_be/auth/JwtUtil.java b/src/main/java/com/ordertogether/team14_be/auth/persistence/JwtUtil.java similarity index 69% rename from src/main/java/com/ordertogether/team14_be/auth/JwtUtil.java rename to src/main/java/com/ordertogether/team14_be/auth/persistence/JwtUtil.java index deaeb9c7..d756f440 100644 --- a/src/main/java/com/ordertogether/team14_be/auth/JwtUtil.java +++ b/src/main/java/com/ordertogether/team14_be/auth/persistence/JwtUtil.java @@ -1,7 +1,9 @@ -package com.ordertogether.team14_be.auth; +package com.ordertogether.team14_be.auth.persistence; +import com.ordertogether.team14_be.auth.persistence.exception.InvalidToken; import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.MalformedJwtException; import io.jsonwebtoken.SignatureAlgorithm; import io.jsonwebtoken.security.Keys; import java.nio.charset.StandardCharsets; @@ -38,4 +40,17 @@ public String generateToken(Long data) { public Claims decodeJwt(String token) { return Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token).getBody(); } + + public boolean vaildToken(String token) throws InvalidToken { + try { + Claims claims = + Jwts.parser() + .setSigningKey(key) + .parseClaimsJws(token) // 토큰 파싱 + .getBody(); + return true; // 유효하다면 true 반환 + } catch (MalformedJwtException e) { + throw new InvalidToken(); + } + } } diff --git a/src/main/java/com/ordertogether/team14_be/auth/persistence/exception/InvalidToken.java b/src/main/java/com/ordertogether/team14_be/auth/persistence/exception/InvalidToken.java new file mode 100644 index 00000000..82052799 --- /dev/null +++ b/src/main/java/com/ordertogether/team14_be/auth/persistence/exception/InvalidToken.java @@ -0,0 +1,7 @@ +package com.ordertogether.team14_be.auth.persistence.exception; + +public class InvalidToken extends IllegalAccessException { + public InvalidToken() { + super("토큰이 유효하지 않습니다."); + } +} diff --git a/src/main/java/com/ordertogether/team14_be/auth/presentation/AuthController.java b/src/main/java/com/ordertogether/team14_be/auth/presentation/AuthController.java index c1342214..a096de4c 100644 --- a/src/main/java/com/ordertogether/team14_be/auth/presentation/AuthController.java +++ b/src/main/java/com/ordertogether/team14_be/auth/presentation/AuthController.java @@ -47,7 +47,6 @@ public ResponseEntity> getToken( @RequestHeader("Authorization") String authorizationHeader, HttpServletResponse httpServletResponse) { String authorizationCode = authorizationHeader.replace("Bearer ", ""); - System.out.println("인가코드:" + authorizationCode); String userKakaoEmail = kakaoAuthService.getKakaoUserEmail(authorizationCode); System.out.println("이메일:" + userKakaoEmail); Optional existMember = memberService.findMemberByEmail(userKakaoEmail); @@ -103,7 +102,8 @@ public ResponseEntity> signUpMember( } @PostMapping("/logout") - public void logout(HttpServletResponse response) { + public ResponseEntity> logout(HttpServletResponse response) { + ResponseCookie deleteCookie = ResponseCookie.from("serviceToken", "") .maxAge(0) @@ -115,5 +115,9 @@ public void logout(HttpServletResponse response) { HttpHeaders headers = new HttpHeaders(); headers.add(HttpHeaders.SET_COOKIE, deleteCookie.toString()); + + return ResponseEntity.ok() + .headers(headers) + .body(ApiResponse.with(HttpStatus.OK, "로그아웃 성공", "")); } } diff --git a/src/main/java/com/ordertogether/team14_be/config/WebConfig.java b/src/main/java/com/ordertogether/team14_be/config/WebConfig.java index 9b911586..6c8dc57a 100644 --- a/src/main/java/com/ordertogether/team14_be/config/WebConfig.java +++ b/src/main/java/com/ordertogether/team14_be/config/WebConfig.java @@ -1,21 +1,33 @@ package com.ordertogether.team14_be.config; +import com.ordertogether.team14_be.auth.persistence.JwtInterceptor; import com.ordertogether.team14_be.member.application.LoginMemberArgumentResolver; import java.util.List; +import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Configuration; import org.springframework.web.method.support.HandlerMethodArgumentResolver; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration +@RequiredArgsConstructor +@EnableWebMvc public class WebConfig implements WebMvcConfigurer { private final LoginMemberArgumentResolver loginMemberArgumentResolver; - - public WebConfig(LoginMemberArgumentResolver loginMemberArgumentResolver) { - this.loginMemberArgumentResolver = loginMemberArgumentResolver; - } + private final JwtInterceptor jwtInterceptor; @Override public void addArgumentResolvers(List argumentResolvers) { argumentResolvers.add(loginMemberArgumentResolver); } + + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry + .addInterceptor(jwtInterceptor) + .addPathPatterns("/**") + .excludePathPatterns( + "/signup", "/api/v1/auth/signup", "/api/v1/auth/login", "/api/v1/spot/**"); + } } diff --git a/src/main/java/com/ordertogether/team14_be/member/application/LoginMemberArgumentResolver.java b/src/main/java/com/ordertogether/team14_be/member/application/LoginMemberArgumentResolver.java index 543bd5a6..aeabaf7a 100644 --- a/src/main/java/com/ordertogether/team14_be/member/application/LoginMemberArgumentResolver.java +++ b/src/main/java/com/ordertogether/team14_be/member/application/LoginMemberArgumentResolver.java @@ -1,6 +1,6 @@ package com.ordertogether.team14_be.member.application; -import com.ordertogether.team14_be.auth.JwtUtil; +import com.ordertogether.team14_be.auth.persistence.JwtUtil; import com.ordertogether.team14_be.member.application.service.MemberService; import com.ordertogether.team14_be.member.persistence.MemberRepository; import com.ordertogether.team14_be.member.presentation.LoginMember; diff --git a/src/main/java/com/ordertogether/team14_be/member/application/exception/NotFoundMember.java b/src/main/java/com/ordertogether/team14_be/member/application/exception/NotFoundMember.java index 23591c70..c7beeff2 100644 --- a/src/main/java/com/ordertogether/team14_be/member/application/exception/NotFoundMember.java +++ b/src/main/java/com/ordertogether/team14_be/member/application/exception/NotFoundMember.java @@ -3,8 +3,7 @@ import java.util.NoSuchElementException; public class NotFoundMember extends NoSuchElementException { - public NotFoundMember() { - super("회원정보가 존재하지 않습니다"); + super("회원정보가 존재하지 않습니다."); } } diff --git a/src/main/java/com/ordertogether/team14_be/member/presentation/MemberController.java b/src/main/java/com/ordertogether/team14_be/member/presentation/MemberController.java index 6251e840..4650ee01 100644 --- a/src/main/java/com/ordertogether/team14_be/member/presentation/MemberController.java +++ b/src/main/java/com/ordertogether/team14_be/member/presentation/MemberController.java @@ -1,17 +1,22 @@ package com.ordertogether.team14_be.member.presentation; +import com.ordertogether.team14_be.auth.persistence.JwtUtil; import com.ordertogether.team14_be.common.web.response.ApiResponse; import com.ordertogether.team14_be.member.application.dto.MemberInfoRequest; import com.ordertogether.team14_be.member.application.dto.MemberInfoResponse; import com.ordertogether.team14_be.member.application.service.MemberService; import com.ordertogether.team14_be.member.persistence.entity.Member; +import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseCookie; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -19,8 +24,8 @@ @RestController @RequestMapping("api/v1/members") public class MemberController { - private final MemberService memberService; + private final JwtUtil jwtUtil; @GetMapping public ResponseEntity> getMemberInfo(@LoginMember Member member) { @@ -38,8 +43,26 @@ public ResponseEntity> modifyMemberInfo( } @DeleteMapping - public ResponseEntity deleteMember(@LoginMember Member member) { - memberService.deleteMember(member.getId()); - return ResponseEntity.ok(ApiResponse.with(HttpStatus.OK, "회원 정보가 삭제되었습니다.", "")); + public ResponseEntity deleteMember( + @RequestHeader("Authorization") String authorizationHeader, + HttpServletResponse httpServletResponse) { + ResponseCookie deleteCookie = + ResponseCookie.from("serviceToken", "") + .maxAge(0) + .httpOnly(true) + .secure(true) + .path("/") + .sameSite("Strict") + .build(); + HttpHeaders headers = new HttpHeaders(); + headers.add(HttpHeaders.SET_COOKIE, deleteCookie.toString()); + + String serviceToken = authorizationHeader.replace("Bearer ", ""); + String stringMemberId = jwtUtil.decodeJwt(serviceToken).getSubject(); + long memberId = Integer.parseInt(stringMemberId); + memberService.deleteMember(memberId); + return ResponseEntity.ok() + .headers(headers) + .body(ApiResponse.with(HttpStatus.OK, "회원탈퇴 성공", "")); } }