diff --git a/backend/src/main/java/io/f1/backend/domain/user/api/UserController.java b/backend/src/main/java/io/f1/backend/domain/user/api/UserController.java new file mode 100644 index 00000000..4cbe5343 --- /dev/null +++ b/backend/src/main/java/io/f1/backend/domain/user/api/UserController.java @@ -0,0 +1,45 @@ +package io.f1.backend.domain.user.api; + +import static io.f1.backend.global.util.SecurityUtils.logout; + +import io.f1.backend.domain.user.app.UserService; +import io.f1.backend.domain.user.dto.SignupRequestDto; +import io.f1.backend.domain.user.dto.UserPrincipal; + +import jakarta.servlet.http.HttpSession; + +import lombok.RequiredArgsConstructor; + +import org.springframework.http.ResponseEntity; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/user/me") +public class UserController { + + private final UserService userService; + + @DeleteMapping + public ResponseEntity deleteCurrentUser( + @AuthenticationPrincipal UserPrincipal userPrincipal, HttpSession httpSession) { + userService.deleteUser(userPrincipal.getUserId()); + logout(httpSession); + return ResponseEntity.noContent().build(); + } + + @PutMapping + public ResponseEntity updateNickname( + @AuthenticationPrincipal UserPrincipal userPrincipal, + @RequestBody SignupRequestDto signupRequest, + HttpSession httpSession) { + userService.updateNickname( + userPrincipal.getUserId(), signupRequest.nickname(), httpSession); + return ResponseEntity.noContent().build(); + } +} diff --git a/backend/src/main/java/io/f1/backend/domain/user/app/UserService.java b/backend/src/main/java/io/f1/backend/domain/user/app/UserService.java index c7e48e56..f23e2b0f 100644 --- a/backend/src/main/java/io/f1/backend/domain/user/app/UserService.java +++ b/backend/src/main/java/io/f1/backend/domain/user/app/UserService.java @@ -32,7 +32,7 @@ public SignupResponseDto signup(HttpSession session, SignupRequestDto signupRequ validateNicknameFormat(nickname); validateNicknameDuplicate(nickname); - User user = updateUserNickname(authenticationUser.userId(), nickname); + User user = initNickname(authenticationUser.userId(), nickname); updateSessionAfterSignup(session, user); SecurityUtils.setAuthentication(user); @@ -68,7 +68,7 @@ public void validateNicknameDuplicate(String nickname) { } @Transactional - public User updateUserNickname(Long userId, String nickname) { + public User initNickname(Long userId, String nickname) { User user = userRepository .findById(userId) @@ -82,4 +82,23 @@ private void updateSessionAfterSignup(HttpSession session, User user) { session.removeAttribute(OAUTH_USER); session.setAttribute(USER, AuthenticationUser.from(user)); } + + @Transactional + public void deleteUser(Long userId) { + User user = + userRepository + .findById(userId) + .orElseThrow(() -> new RuntimeException("E404001: 존재하지 않는 회원입니다.")); + userRepository.delete(user); + } + + @Transactional + public void updateNickname(Long userId, String newNickname, HttpSession session) { + validateNicknameFormat(newNickname); + validateNicknameDuplicate(newNickname); + + User user = initNickname(userId, newNickname); + session.setAttribute(USER, AuthenticationUser.from(user)); + SecurityUtils.setAuthentication(user); + } } diff --git a/backend/src/main/java/io/f1/backend/global/config/SecurityConfig.java b/backend/src/main/java/io/f1/backend/global/config/SecurityConfig.java index ebcfc42e..2866dc7e 100644 --- a/backend/src/main/java/io/f1/backend/global/config/SecurityConfig.java +++ b/backend/src/main/java/io/f1/backend/global/config/SecurityConfig.java @@ -42,6 +42,8 @@ public SecurityFilterChain userFilterChain(HttpSecurity http) throws Exception { .permitAll() .requestMatchers("/ws/**") .authenticated() + .requestMatchers("/user/me") + .hasRole("USER") .anyRequest() .authenticated()) .formLogin(AbstractHttpConfigurer::disable) diff --git a/backend/src/main/java/io/f1/backend/global/config/WebConfig.java b/backend/src/main/java/io/f1/backend/global/config/WebConfig.java index 8d093eec..a80ae64c 100644 --- a/backend/src/main/java/io/f1/backend/global/config/WebConfig.java +++ b/backend/src/main/java/io/f1/backend/global/config/WebConfig.java @@ -1,6 +1,8 @@ package io.f1.backend.global.config; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.web.filter.HiddenHttpMethodFilter; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @@ -14,4 +16,9 @@ public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/images/thumbnail/**") .addResourceLocations("file:images/thumbnail/"); } + + @Bean + public HiddenHttpMethodFilter hiddenHttpMethodFilter() { + return new HiddenHttpMethodFilter(); + } } diff --git a/backend/src/main/java/io/f1/backend/global/util/SecurityUtils.java b/backend/src/main/java/io/f1/backend/global/util/SecurityUtils.java index 5915e5d2..9a4530a0 100644 --- a/backend/src/main/java/io/f1/backend/global/util/SecurityUtils.java +++ b/backend/src/main/java/io/f1/backend/global/util/SecurityUtils.java @@ -3,6 +3,8 @@ import io.f1.backend.domain.user.dto.UserPrincipal; import io.f1.backend.domain.user.entity.User; +import jakarta.servlet.http.HttpSession; + import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; @@ -37,4 +39,15 @@ public static Long getCurrentUserId() { public static String getCurrentUserNickname() { return getCurrentUserPrincipal().getUserNickname(); } + + public static void logout(HttpSession session) { + if (session != null) { + session.invalidate(); + } + clearAuthentication(); + } + + private static void clearAuthentication() { + SecurityContextHolder.clearContext(); + } }