Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
Expand All @@ -15,6 +16,7 @@
import team.wego.wegobackend.auth.exception.UserAlreadyExistsException;
import team.wego.wegobackend.auth.exception.UserNotFoundException;
import team.wego.wegobackend.common.exception.AppErrorCode;
import team.wego.wegobackend.common.response.ApiResponse;
import team.wego.wegobackend.common.security.Role;
import team.wego.wegobackend.common.security.exception.ExpiredTokenException;
import team.wego.wegobackend.common.security.jwt.JwtTokenProvider;
Expand Down Expand Up @@ -106,4 +108,17 @@ public RefreshResponse refresh(String refreshToken) {

return RefreshResponse.of(newAccessToken, expiresIn);
}

/**
* 회원탈퇴
*/
@Transactional
public void withDraw(Long userId) {

User user = userRepository.findById(userId)
.orElseThrow(UserNotFoundException::new);

user.updatedeleted(true);

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
Expand All @@ -19,6 +21,7 @@
import team.wego.wegobackend.auth.application.dto.response.RefreshResponse;
import team.wego.wegobackend.auth.application.dto.response.SignupResponse;
import team.wego.wegobackend.common.response.ApiResponse;
import team.wego.wegobackend.common.security.CustomUserDetails;
import team.wego.wegobackend.common.security.jwt.JwtTokenProvider;

@Slf4j
Expand Down Expand Up @@ -71,14 +74,8 @@ public ResponseEntity<ApiResponse<LoginResponse>> login(
*/
@PostMapping("/logout")
public ResponseEntity<ApiResponse<Void>> logout(HttpServletResponse response) {
// Refresh Token 쿠키만 삭제
Cookie deleteCookie = new Cookie("refreshToken", null);
deleteCookie.setPath("/");
deleteCookie.setMaxAge(0);
deleteCookie.setHttpOnly(true);
deleteCookie.setSecure(true);
deleteCookie.setAttribute("SameSite", "Strict");
response.addCookie(deleteCookie);

deleteRefreshTokenCookie(response);

return ResponseEntity
.status(HttpStatus.NO_CONTENT)
Expand All @@ -88,6 +85,23 @@ public ResponseEntity<ApiResponse<Void>> logout(HttpServletResponse response) {
));
}

/**
* 회원탈퇴
* */
@DeleteMapping("/withdraw")
public ResponseEntity<ApiResponse<String>> withDraw(
@AuthenticationPrincipal CustomUserDetails userDetails,
HttpServletResponse response
) {

authService.withDraw(userDetails.getId());
deleteRefreshTokenCookie(response);

return ResponseEntity
.status(HttpStatus.OK)
.body(ApiResponse.success(200, "회원탈퇴 성공"));
}

/**
* Access Token 재발급
*/
Expand Down Expand Up @@ -121,5 +135,18 @@ private Cookie createRefreshTokenCookie(String refreshToken) {
cookie.setAttribute("SameSite", "Strict");
return cookie;
}

/**
* Refresh Token HttpOnly 쿠키 제거
*/
private void deleteRefreshTokenCookie(HttpServletResponse response) {
Cookie deleteCookie = new Cookie("refreshToken", null);
deleteCookie.setPath("/");
deleteCookie.setMaxAge(0);
deleteCookie.setHttpOnly(true);
deleteCookie.setSecure(true);
deleteCookie.setAttribute("SameSite", "Strict");
response.addCookie(deleteCookie);
}
//TODO : 개발 토큰 발급 엔드포인트 추가
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

문서의 회원탈퇴 설명(DB Soft Delete)와 실제 구현 불일치

Docs 인터페이스 시그니처는 AuthController 구현과 잘 맞지만, 설명에는 *"DB Soft Delete + refreshCookie 제거"*라고 되어 있는 반면 현재 AuthController.withDraw는 refresh 쿠키 삭제만 수행하고, AuthService.withDraw를 호출하지 않습니다.

문서와 실제 동작을 일치시키기 위해서는:

  • AuthController.withDraw에서 authService.withDraw(userDetails.getId())를 호출해 soft delete를 수행하거나,
  • (만약 의도적으로 아직 미구현이라면) 설명을 수정해 현재 동작을 정확하게 표현해야 합니다.

현재 상태는 API 계약과 구현이 어긋난 상태이므로 정리가 필요해 보입니다.

Also applies to: 17-17, 38-42

🤖 Prompt for AI Agents
In src/main/java/team/wego/wegobackend/auth/presentation/AuthControllerDocs.java
around lines 8, 17 and 38-42, the Javadoc/description claims "DB Soft Delete +
refreshCookie removal" but the actual AuthController.withDraw implementation
only removes the refresh cookie and does not call AuthService.withDraw; either
update the controller to call authService.withDraw(userDetails.getId()) before
removing the cookie so the soft-delete is performed, or update the docs text to
accurately reflect that only the refresh cookie is removed (no DB soft delete);
pick one approach, implement the corresponding change, and keep the method
signature/comments consistent with the chosen behavior.

import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.RequestBody;
import team.wego.wegobackend.auth.application.dto.request.LoginRequest;
Expand All @@ -13,6 +14,7 @@
import team.wego.wegobackend.auth.application.dto.response.RefreshResponse;
import team.wego.wegobackend.auth.application.dto.response.SignupResponse;
import team.wego.wegobackend.common.response.ApiResponse;
import team.wego.wegobackend.common.security.CustomUserDetails;

@Tag(name = "인증/인가 API", description = "인증 및 인가에 대한 API 리스트 \uD83D\uDC08")
public interface AuthControllerDocs {
Expand All @@ -32,5 +34,11 @@ ResponseEntity<ApiResponse<LoginResponse>> login(
@Operation(summary = "액세스 토큰 재발급", description = "리프레시 토큰 만료가 안되었을 경우 액세스 토큰을 재발급합니다.")
ResponseEntity<ApiResponse<RefreshResponse>> refresh(
@CookieValue(name = "refreshToken", required = false) String refreshToken);


@Operation(summary = "회원탈퇴", description = "DB Soft Delete + refreshCookie 제거")
ResponseEntity<ApiResponse<String>> withDraw(
@AuthenticationPrincipal CustomUserDetails userDetails,
HttpServletResponse response
);

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
public class SecurityEndpoints {

public static final String[] PUBLIC_PATTERNS = {
"/api/v*/auth/**",
"/api/v*/auth/signup",
"/api/v*/auth/login",
"/api/v*/auth/refresh",
"/api/v*/health",
"/h2-console/**",
"/error",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ public void follow(String followNickname, Long followerId) {
.follower(follower)
.follow(follow)
.build());

follower.increaseFolloweeCount();
follow.increaseFollowerCount();
}

public void unFollow(String unFollowNickname, Long followerId) {
Expand All @@ -61,5 +64,8 @@ public void unFollow(String unFollowNickname, Long followerId) {
.orElseThrow(NotFoundFollowException::new);

followRepository.delete(followEntity);

follower.decreaseFolloweeCount();
follow.decreaseFollowerCount();
}
}
4 changes: 4 additions & 0 deletions src/main/java/team/wego/wegobackend/user/domain/User.java
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,10 @@ public void updateNotificationEnabled(Boolean flag) {
this.notificationEnabled = flag;
}

public void updatedeleted(Boolean flag) {
this.deleted = flag;
}

public void updateMbti(String mbti) {
this.mbti = mbti;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,6 @@ public ResponseEntity<ApiResponse<String>> follow(
.body(ApiResponse.success(201, "팔로우 성공"));
}

//TODO : 팔로우 삭제 API
@DeleteMapping("/unfollow")
public ResponseEntity<ApiResponse<String>> unFollow(
@AuthenticationPrincipal CustomUserDetails userDetails,
Expand All @@ -122,8 +121,8 @@ public ResponseEntity<ApiResponse<String>> unFollow(
followService.unFollow(unFollowNickname, userDetails.getId());

return ResponseEntity
.status(HttpStatus.CREATED)
.body(ApiResponse.success(201, "팔로우 취소 성공"));
.status(HttpStatus.OK)
.body(ApiResponse.success(200, "팔로우 취소 성공"));
}

//TODO : 팔로우 목록 조회 API
Expand Down