diff --git a/src/main/java/com/back/domain/mybar/controller/MyBarController.java b/src/main/java/com/back/domain/mybar/controller/MyBarController.java index 8a6297df..d8047ffd 100644 --- a/src/main/java/com/back/domain/mybar/controller/MyBarController.java +++ b/src/main/java/com/back/domain/mybar/controller/MyBarController.java @@ -2,7 +2,6 @@ import com.back.domain.mybar.dto.MyBarListResponseDto; import com.back.domain.mybar.service.MyBarService; -import com.back.global.exception.ServiceException; import com.back.global.rsData.RsData; import com.back.global.security.SecurityUser; import io.swagger.v3.oas.annotations.Operation; @@ -10,6 +9,7 @@ import jakarta.validation.constraints.Min; import lombok.RequiredArgsConstructor; import org.springframework.format.annotation.DateTimeFormat; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; @@ -20,6 +20,7 @@ @RequestMapping("/me/bar") @RequiredArgsConstructor @Validated +@PreAuthorize("isAuthenticated()") public class MyBarController { /** @@ -40,14 +41,13 @@ public class MyBarController { @GetMapping @Operation(summary = "내 바 목록", description = "내가 킵한 칵테일 목록 조회. 무한 스크롤 커서 지원") public RsData getMyBarList( - @AuthenticationPrincipal(errorOnInvalidType = false) SecurityUser principal, + @AuthenticationPrincipal SecurityUser principal, @RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime lastKeptAt, @RequestParam(required = false) Long lastId, @RequestParam(defaultValue = "20") @Min(1) @Max(100) int limit ) { - Long userId = principal != null ? principal.getId() : null; - if (userId == null) throw new ServiceException(401, "로그인이 필요합니다."); + Long userId = principal.getId(); MyBarListResponseDto body = myBarService.getMyBar(userId, lastKeptAt, lastId, limit); return RsData.successOf(body); } @@ -61,11 +61,10 @@ public RsData getMyBarList( @PostMapping("/{cocktailId}/keep") @Operation(summary = "킵 추가/복원", description = "해당 칵테일을 내 바에 킵합니다. 이미 삭제 상태면 복원") public RsData keep( - @AuthenticationPrincipal(errorOnInvalidType = false) SecurityUser principal, + @AuthenticationPrincipal SecurityUser principal, @PathVariable Long cocktailId ) { - Long userId = principal != null ? principal.getId() : null; - if (userId == null) throw new ServiceException(401, "로그인이 필요합니다."); + Long userId = principal.getId(); myBarService.keep(userId, cocktailId); return RsData.of(201, "kept"); // Aspect가 HTTP 201로 설정 } @@ -79,11 +78,10 @@ public RsData keep( @DeleteMapping("/{cocktailId}/keep") @Operation(summary = "킵 해제", description = "내 바에서 해당 칵테일을 삭제(소프트 삭제, 멱등)") public RsData unkeep( - @AuthenticationPrincipal(errorOnInvalidType = false) SecurityUser principal, + @AuthenticationPrincipal SecurityUser principal, @PathVariable Long cocktailId ) { - Long userId = principal != null ? principal.getId() : null; - if (userId == null) throw new ServiceException(401, "로그인이 필요합니다."); + Long userId = principal.getId(); myBarService.unkeep(userId, cocktailId); return RsData.of(200, "deleted"); } diff --git a/src/main/java/com/back/domain/myhistory/controller/MyHistoryController.java b/src/main/java/com/back/domain/myhistory/controller/MyHistoryController.java index 383dbb00..47b71a10 100644 --- a/src/main/java/com/back/domain/myhistory/controller/MyHistoryController.java +++ b/src/main/java/com/back/domain/myhistory/controller/MyHistoryController.java @@ -6,11 +6,13 @@ import com.back.domain.myhistory.dto.MyHistoryLikedPostListDto; import com.back.domain.myhistory.service.MyHistoryService; import com.back.global.rsData.RsData; +import com.back.global.security.SecurityUser; import io.swagger.v3.oas.annotations.Operation; import jakarta.validation.constraints.Max; import jakarta.validation.constraints.Min; import lombok.RequiredArgsConstructor; import org.springframework.format.annotation.DateTimeFormat; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; @@ -21,6 +23,7 @@ @RequestMapping("/me") @RequiredArgsConstructor @Validated +@PreAuthorize("isAuthenticated()") public class MyHistoryController { private final MyHistoryService myHistoryService; @@ -36,11 +39,12 @@ public class MyHistoryController { @GetMapping("/posts") @Operation(summary = "내 게시글 목록", description = "내가 작성한 게시글 최신순 목록. 무한스크롤 파라미터 지원") public RsData getMyPosts( - @AuthenticationPrincipal(expression = "id") Long userId, + @AuthenticationPrincipal SecurityUser principal, @RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime lastCreatedAt, @RequestParam(required = false) Long lastId, @RequestParam(defaultValue = "20") @Min(1) @Max(100) int limit ) { + Long userId = principal.getId(); MyHistoryPostListDto body = myHistoryService.getMyPosts(userId, lastCreatedAt, lastId, limit); return RsData.successOf(body); } @@ -54,9 +58,10 @@ public RsData getMyPosts( @GetMapping("/posts/{id}") @Operation(summary = "내 게시글로 이동", description = "내가 작성한 게시글 상세 링크 정보 반환") public RsData goFromPost( - @AuthenticationPrincipal(expression = "id") Long userId, + @AuthenticationPrincipal SecurityUser principal, @PathVariable("id") Long postId ) { + Long userId = principal.getId(); var body = myHistoryService.getPostLinkFromMyPost(userId, postId); return RsData.successOf(body); } @@ -72,11 +77,12 @@ public RsData goFromPo @GetMapping("/comments") @Operation(summary = "내 댓글 목록", description = "내가 작성한 댓글 최신순 목록. 무한스크롤 파라미터 지원") public RsData getMyComments( - @AuthenticationPrincipal(expression = "id") Long userId, + @AuthenticationPrincipal SecurityUser principal, @RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime lastCreatedAt, @RequestParam(required = false) Long lastId, @RequestParam(defaultValue = "20") @Min(1) @Max(100) int limit ) { + Long userId = principal.getId(); MyHistoryCommentListDto body = myHistoryService.getMyComments(userId, lastCreatedAt, lastId, limit); return RsData.successOf(body); } @@ -92,11 +98,12 @@ public RsData getMyComments( @GetMapping("/likes") @Operation(summary = "좋아요한 게시글 목록", description = "좋아요한 게시글 최신순 목록. 무한스크롤 파라미터 지원") public RsData getMyLikedPosts( - @AuthenticationPrincipal(expression = "id") Long userId, + @AuthenticationPrincipal SecurityUser principal, @RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime lastCreatedAt, @RequestParam(required = false) Long lastId, @RequestParam(defaultValue = "20") @Min(1) @Max(100) int limit ) { + Long userId = principal.getId(); MyHistoryLikedPostListDto body = myHistoryService.getMyLikedPosts(userId, lastCreatedAt, lastId, limit); return RsData.successOf(body); } @@ -110,9 +117,10 @@ public RsData getMyLikedPosts( @GetMapping("/comments/{id}") @Operation(summary = "댓글에서 게시글 이동", description = "내 댓글이 달린 게시글 상세 링크 정보 반환") public RsData goFromComment( - @AuthenticationPrincipal(expression = "id") Long userId, + @AuthenticationPrincipal SecurityUser principal, @PathVariable("id") Long commentId ) { + Long userId = principal.getId(); var body = myHistoryService.getPostLinkFromMyComment(userId, commentId); return RsData.successOf(body); } @@ -126,9 +134,10 @@ public RsData goFromComment( @GetMapping("/likes/{id}") @Operation(summary = "좋아요 목록에서 이동", description = "좋아요한 게시글 상세 링크 정보 반환") public RsData goFromLikedPost( - @AuthenticationPrincipal(expression = "id") Long userId, + @AuthenticationPrincipal SecurityUser principal, @PathVariable("id") Long postId ) { + Long userId = principal.getId(); var body = myHistoryService.getPostLinkFromMyLikedPost(userId, postId); return RsData.successOf(body); } diff --git a/src/main/java/com/back/domain/notification/controller/NotificationController.java b/src/main/java/com/back/domain/notification/controller/NotificationController.java index 00ee1dde..845860a0 100644 --- a/src/main/java/com/back/domain/notification/controller/NotificationController.java +++ b/src/main/java/com/back/domain/notification/controller/NotificationController.java @@ -7,12 +7,14 @@ import com.back.domain.notification.service.NotificationService; import com.back.domain.notification.service.NotificationSettingService; import com.back.global.rsData.RsData; +import com.back.global.security.SecurityUser; import io.swagger.v3.oas.annotations.Operation; import jakarta.validation.Valid; import jakarta.validation.constraints.Max; import jakarta.validation.constraints.Min; import lombok.RequiredArgsConstructor; import org.springframework.format.annotation.DateTimeFormat; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; @@ -24,6 +26,7 @@ @RequestMapping("/me") @RequiredArgsConstructor @Validated +@PreAuthorize("isAuthenticated()") public class NotificationController { /** @@ -59,11 +62,12 @@ public SseEmitter subscribe() { @GetMapping("/notifications") @Operation(summary = "알림 목록 조회", description = "무한스크롤(nextCreatedAt, nextId) 기반 최신순 조회. limit 1~100") public RsData getNotifications( - @AuthenticationPrincipal(expression = "id") Long userId, + @AuthenticationPrincipal SecurityUser principal, @RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime lastCreatedAt, @RequestParam(required = false) Long lastId, @RequestParam(defaultValue = "20") @Min(1) @Max(100) int limit ) { + Long userId = principal.getId(); NotificationListResponseDto body = notificationService.getNotifications(userId, lastCreatedAt, lastId, limit); return RsData.successOf(body); } @@ -77,8 +81,9 @@ public RsData getNotifications( @GetMapping("/notification-setting") @Operation(summary = "알림 설정 조회", description = "사용자 알림 on/off 상태 조회. 미생성 시 기본 true 반환") public RsData getMyNotificationSetting( - @AuthenticationPrincipal(expression = "id") Long userId + @AuthenticationPrincipal SecurityUser principal ) { + Long userId = principal.getId(); NotificationSettingDto body = notificationSettingService.getMySetting(userId); return RsData.successOf(body); } @@ -93,9 +98,10 @@ public RsData getMyNotificationSetting( @PatchMapping("/notification-setting") @Operation(summary = "알림 설정 변경", description = "enabled 값을 true/false로 설정(멱등)") public RsData setMyNotificationSetting( - @AuthenticationPrincipal(expression = "id") Long userId, + @AuthenticationPrincipal SecurityUser principal, @Valid @RequestBody NotificationSettingUpdateRequestDto req ) { + Long userId = principal.getId(); NotificationSettingDto body = notificationSettingService.setMySetting(userId, req.enabled()); return RsData.successOf(body); } @@ -110,9 +116,10 @@ public RsData setMyNotificationSetting( @PostMapping("/notifications/{id}") @Operation(summary = "읽음 처리 후 이동 정보", description = "알림을 읽음 처리하고 해당 게시글 ID와 API URL 반환") public RsData goPostLink( - @AuthenticationPrincipal(expression = "id") Long userId, + @AuthenticationPrincipal SecurityUser principal, @PathVariable("id") Long notificationId ) { + Long userId = principal.getId(); var body = notificationService.markAsReadAndGetPostLink(userId, notificationId); return RsData.successOf(body); } diff --git a/src/main/java/com/back/domain/profile/controller/ProfileController.java b/src/main/java/com/back/domain/profile/controller/ProfileController.java index f7d9eca3..5c6eebea 100644 --- a/src/main/java/com/back/domain/profile/controller/ProfileController.java +++ b/src/main/java/com/back/domain/profile/controller/ProfileController.java @@ -5,15 +5,18 @@ import com.back.domain.profile.service.ProfileService; import com.back.domain.user.service.UserService; import com.back.global.rsData.RsData; +import com.back.global.security.SecurityUser; import jakarta.validation.Valid; import io.swagger.v3.oas.annotations.Operation; import lombok.RequiredArgsConstructor; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.*; @RestController @RequestMapping("/me/profile") @RequiredArgsConstructor +@PreAuthorize("isAuthenticated()") public class ProfileController { /** @@ -33,7 +36,8 @@ public class ProfileController { @GetMapping @Operation(summary = "내 프로필 요약 조회", description = "닉네임, 알콜도수(등급/라벨), 작성/댓글/좋아요 카운트를 반환") - public RsData getProfile(@AuthenticationPrincipal(expression = "id") Long userId) { + public RsData getProfile(@AuthenticationPrincipal SecurityUser principal) { + Long userId = principal.getId(); ProfileResponseDto body = profileService.getProfile(userId); return RsData.successOf(body); // code=200, message="success" } @@ -50,9 +54,10 @@ public RsData getProfile(@AuthenticationPrincipal(expression @PatchMapping @Operation(summary = "프로필 수정(닉네임)", description = "닉네임은 1~10자, 중복 불가") public RsData patchNickname( - @AuthenticationPrincipal(expression = "id") Long userId, + @AuthenticationPrincipal SecurityUser principal, @Valid @RequestBody ProfileUpdateRequestDto request ) { + Long userId = principal.getId(); ProfileResponseDto body = profileService.updateProfile(userId, request); return RsData.successOf(body); } diff --git a/src/main/java/com/back/global/security/SecurityConfig.java b/src/main/java/com/back/global/security/SecurityConfig.java index b5356587..fdb4a597 100644 --- a/src/main/java/com/back/global/security/SecurityConfig.java +++ b/src/main/java/com/back/global/security/SecurityConfig.java @@ -3,6 +3,7 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; 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; @@ -17,6 +18,7 @@ @Configuration @EnableWebSecurity +@EnableMethodSecurity public class SecurityConfig { @Value("${custom.site.frontUrl}")