diff --git a/src/main/java/life/mosu/mosuserver/infra/kmc/KmcCryptoManager.java b/src/main/java/life/mosu/mosuserver/infra/kmc/KmcCryptoManager.java index 23efd5df..eac5790f 100644 --- a/src/main/java/life/mosu/mosuserver/infra/kmc/KmcCryptoManager.java +++ b/src/main/java/life/mosu/mosuserver/infra/kmc/KmcCryptoManager.java @@ -1,33 +1,34 @@ package life.mosu.mosuserver.infra.kmc; import com.icert.comm.secu.IcertSecuManager; +import java.text.SimpleDateFormat; +import java.util.Date; import life.mosu.mosuserver.infra.kmc.dto.KmcCertRequest; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; -import java.text.SimpleDateFormat; -import java.util.Date; @Slf4j @Component @RequiredArgsConstructor public class KmcCryptoManager { - private final KmcProperties kmcProperties; - private final IcertSecuManager secuManager; - private static final String EXTEND_VAR = "0000000000000000"; private static final String DELIMITER = "/"; + private final KmcProperties kmcProperties; + private final IcertSecuManager secuManager; - /** - * KMC 본인인증 요청 데이터(tr_cert)를 암호화 - */ public String encryptRequestData(KmcCertRequest request, String certNum) { String currentDate = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()); String plusInfo = request.serviceTerm(); - String rawData = String.join(DELIMITER, - kmcProperties.getCpId(), kmcProperties.getUrlCode(), certNum, currentDate, "M", + String rawData = String.join( + DELIMITER, + kmcProperties.getCpId(), + kmcProperties.getUrlCode(), + certNum, + currentDate, + "M", "", "", "", "", "", "", plusInfo, EXTEND_VAR ); @@ -38,38 +39,23 @@ public String encryptRequestData(KmcCertRequest request, String certNum) { return secuManager.getEnc(enc_tr_cert_1 + DELIMITER + hmacMsg + DELIMITER + EXTEND_VAR, ""); } - /** - * KMC 응답 데이터(rec_cert)를 복호화하고 무결성을 검증 - * @return 2차 복호화까지 완료된 최종 사용자 정보 문자열 - */ public String decryptResponseData(String recCert) { try { - // 1차 복호화 String firstDecrypted = decrypt(recCert); - - // 데이터와 HMAC(무결성 검증 값) 분리 int firstIdx = firstDecrypted.indexOf(DELIMITER); String encPara = firstDecrypted.substring(0, firstIdx); - String receivedHmac = firstDecrypted.substring(firstIdx + 1, firstDecrypted.lastIndexOf(DELIMITER)); - - // 무결성 검증 + String receivedHmac = firstDecrypted.substring(firstIdx + 1, + firstDecrypted.lastIndexOf(DELIMITER)); String generatedHmac = secuManager.getMsg(encPara); if (!generatedHmac.equals(receivedHmac)) { throw new SecurityException("KMC 데이터의 위변조가 의심됩니다."); } - - // 2차 복호화하여 최종 데이터 반환 return decrypt(encPara); } catch (Exception e) { throw new RuntimeException("KMC 인증 결과를 처리하는 중 오류가 발생했습니다.", e); } } - /** - * KMC에서 받은 암호화된 데이터를 복호화 - * @param encryptedData KMC로부터 받은 암호화된 데이터 - * @return 복호화된 문자열 - */ public String decrypt(String encryptedData) { return secuManager.getDec(encryptedData, ""); } diff --git a/src/main/java/life/mosu/mosuserver/infra/kmc/KmcDataMapper.java b/src/main/java/life/mosu/mosuserver/infra/kmc/KmcDataMapper.java index a4c1be54..4431c0d5 100644 --- a/src/main/java/life/mosu/mosuserver/infra/kmc/KmcDataMapper.java +++ b/src/main/java/life/mosu/mosuserver/infra/kmc/KmcDataMapper.java @@ -6,100 +6,52 @@ import life.mosu.mosuserver.infra.kmc.dto.KmcUserInfo; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.codec.binary.Base32; import org.springframework.stereotype.Component; -import org.springframework.util.StringUtils; - @Slf4j - @Component - @RequiredArgsConstructor - public class KmcDataMapper { - - private final KmcCryptoManager kmcCryptoManager; - private final OneTimeTokenProvider tokenProvider; - - private static final String DELIMITER = "/"; - private static final int MIN_FIELD_COUNT = 18; - - // KMC 응답 필드 인덱스를 상수로 정의하여 매직 넘버 제거 - private static final int CERT_NUM_INDEX = 0; - private static final int DATE_INDEX = 1; - private static final int CI_INDEX = 2; - private static final int PHONE_NO_INDEX = 3; - private static final int PHONE_CORP_INDEX = 4; - private static final int BIRTH_INDEX = 5; - private static final int GENDER_INDEX = 6; - private static final int NAME_INDEX = 8; - private static final int RESULT_SUCCESS_INDEX = 9; // 성공여부 - private static final int PLUS_INFO_INDEX = 16; - private static final int DI_INDEX = 17; - - /** - * 복호화된 KMC 최종 데이터 문자열을 KmcUserInfo DTO로 변환합니다. - */ - public KmcUserInfo mapToUserInfo(String finalDecryptedData) { - String[] tokens = finalDecryptedData.split(DELIMITER, -1); - if (tokens.length < MIN_FIELD_COUNT) { - throw new CustomRuntimeException(ErrorCode.INVALID_TOKEN); - } - - if (!tokens[RESULT_SUCCESS_INDEX].equals("Y")) { - throw new CustomRuntimeException(ErrorCode.VERIFICATION_FAILED); - } - - logDecryptedData(tokens); - - String name = tokens[NAME_INDEX]; - String birth = tokens[BIRTH_INDEX]; - String phoneNo = tokens[PHONE_NO_INDEX]; - String gender = tokens[GENDER_INDEX]; - - String servieTerm = tokens[PLUS_INFO_INDEX]; - String signUpToken = tokenProvider.generateOneTimeToken(tokens[CERT_NUM_INDEX]); - - return KmcUserInfo.of(name, birth, phoneNo, gender, servieTerm, signUpToken); - } - - // production 시 삭제 - private void logDecryptedData(String[] tokens) { - if (!log.isInfoEnabled()) return; - - String ci = decryptCiDiValue(tokens[CI_INDEX]); - String di = decryptCiDiValue(tokens[DI_INDEX]); - - log.info("[KMCIS] Parsed User Information:"); - log.info(" - CertNum: {}", tokens[CERT_NUM_INDEX]); - log.info(" - Name: {}", tokens[NAME_INDEX]); - log.info(" - PhoneNo: {}", tokens[PHONE_NO_INDEX]); - log.info(" - Decrypted CI: {}", ci); - log.info(" - Decrypted DI: {}", di); - log.info(" - PlusInfo: {}", tokens[PLUS_INFO_INDEX]); - - logPlusInfoDetail(tokens[PLUS_INFO_INDEX]); +@Slf4j +@Component +@RequiredArgsConstructor +public class KmcDataMapper { + + private static final String DELIMITER = "/"; + private static final int MIN_FIELD_COUNT = 18; + private static final int CERT_NUM_INDEX = 0; + private static final int PHONE_NO_INDEX = 3; + private static final int BIRTH_INDEX = 5; + private static final int GENDER_INDEX = 6; + private static final int NAME_INDEX = 8; + private static final int RESULT_SUCCESS_INDEX = 9; // 성공여부 + private static final int PLUS_INFO_INDEX = 16; + private final OneTimeTokenProvider tokenProvider; + + /** + * 복호화된 KMC 최종 데이터 문자열을 KmcUserInfo DTO로 변환합니다. + */ + public KmcUserInfo mapToUserInfo(String finalDecryptedData) { + String[] tokens = finalDecryptedData.split(DELIMITER, -1); + if (tokens.length < MIN_FIELD_COUNT) { + throw new CustomRuntimeException(ErrorCode.INVALID_TOKEN); } - // production 시 삭제 - private void logPlusInfoDetail(String plusInfo) { - if (!StringUtils.hasText(plusInfo) || !plusInfo.contains("@")) return; - - String[] parts = plusInfo.split("@", -1); - if (parts.length == 3) { - byte[] decodedBytes = new Base32().decode(parts[1]); - String decodedPassword = new String(decodedBytes); - log.info(" - Parsed PlusInfo -> loginId: {}, password(decoded): {}, term: {}", parts[0], decodedPassword, parts[2]); - } + if (!tokens[RESULT_SUCCESS_INDEX].equals("Y")) { + throw new CustomRuntimeException(ErrorCode.VERIFICATION_FAILED); } - // CI/DI 복호화 유틸리티 - private String decryptCiDiValue(String encryptedValue) { - if (StringUtils.hasText(encryptedValue)) { - try { - return kmcCryptoManager.decrypt(encryptedValue); - } catch (Exception e) { - log.warn("Failed to decrypt CI/DI value.", e); - return "DECRYPTION_FAILED"; - } - } - return "EMPTY"; - } - } \ No newline at end of file + String name = tokens[NAME_INDEX]; + String birth = tokens[BIRTH_INDEX]; + String phoneNo = tokens[PHONE_NO_INDEX]; + String gender = tokens[GENDER_INDEX]; + String serviceTerm = tokens[PLUS_INFO_INDEX]; + String signUpToken = tokenProvider.generateOneTimeToken(tokens[CERT_NUM_INDEX]); + + // production시 삭제 + log.info("[KMCIS] Parsed User Information:"); + log.info(" - CertNum: {}", tokens[CERT_NUM_INDEX]); + log.info(" - Name: {}", tokens[NAME_INDEX]); + log.info(" - PhoneNo: {}", tokens[PHONE_NO_INDEX]); + log.info(" - PlusInfo: {}", tokens[PLUS_INFO_INDEX]); + log.info(" - PlusInfo -> {}", tokens[PLUS_INFO_INDEX]); + + return KmcUserInfo.of(name, birth, phoneNo, gender, serviceTerm, signUpToken); + } +} \ No newline at end of file diff --git a/src/main/java/life/mosu/mosuserver/presentation/admin/AdminApplicationController.java b/src/main/java/life/mosu/mosuserver/presentation/admin/AdminApplicationController.java index 06b96790..3eb2697c 100644 --- a/src/main/java/life/mosu/mosuserver/presentation/admin/AdminApplicationController.java +++ b/src/main/java/life/mosu/mosuserver/presentation/admin/AdminApplicationController.java @@ -14,6 +14,7 @@ import org.springframework.data.web.PageableDefault; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; @@ -27,7 +28,7 @@ public class AdminApplicationController { private final AdminApplicationService adminApplicationService; @GetMapping() -// @PreAuthorize("isAuthenticated() and hasRole('ADMIN')") + @PreAuthorize("isAuthenticated() and hasRole('ADMIN')") public ResponseEntity>> getAll( @Valid @ModelAttribute ApplicationFilter filter, @PageableDefault(size = 10) Pageable pageable @@ -43,6 +44,7 @@ public ResponseEntity>> getAll( fileName = "신청 목록.xlsx", dtoClass = ApplicationExcelDto.class ) + @PreAuthorize("isAuthenticated() and hasRole('ADMIN')") public List downloadApplicationInfo() { return adminApplicationService.getExcelData(); } diff --git a/src/main/java/life/mosu/mosuserver/presentation/admin/AdminBannerController.java b/src/main/java/life/mosu/mosuserver/presentation/admin/AdminBannerController.java index 0147c812..eb852b2f 100644 --- a/src/main/java/life/mosu/mosuserver/presentation/admin/AdminBannerController.java +++ b/src/main/java/life/mosu/mosuserver/presentation/admin/AdminBannerController.java @@ -9,6 +9,7 @@ import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @@ -24,7 +25,8 @@ public class AdminBannerController { private final AdminBannerService adminBannerService; - @PostMapping() + @PostMapping + @PreAuthorize("isAuthenticated() and hasRole('ADMIN')") public ResponseEntity> create( @RequestBody BannerRequest request) { adminBannerService.create(request); @@ -32,7 +34,8 @@ public ResponseEntity> create( ApiResponseWrapper.success(HttpStatus.OK, "배너 등록 성공")); } - @GetMapping() + @GetMapping + @PreAuthorize("isAuthenticated() and hasRole('ADMIN')") public ResponseEntity>> getAll() { List responses = adminBannerService.getAll(); return ResponseEntity.ok( @@ -40,6 +43,7 @@ public ResponseEntity>> getAll() { } @GetMapping("/{bannerId}") + @PreAuthorize("isAuthenticated() and hasRole('ADMIN')") public ResponseEntity> getByBannerId( @PathVariable("bannerId") Long bannerId ) { @@ -48,6 +52,7 @@ public ResponseEntity> getByBannerId( } @DeleteMapping("/{bannerId}") + @PreAuthorize("isAuthenticated() and hasRole('ADMIN')") public ResponseEntity> deleteByBannerId( @PathVariable("bannerId") Long bannerId ) { diff --git a/src/main/java/life/mosu/mosuserver/presentation/admin/AdminDashboardController.java b/src/main/java/life/mosu/mosuserver/presentation/admin/AdminDashboardController.java index ab0594be..4ee6e698 100644 --- a/src/main/java/life/mosu/mosuserver/presentation/admin/AdminDashboardController.java +++ b/src/main/java/life/mosu/mosuserver/presentation/admin/AdminDashboardController.java @@ -6,6 +6,7 @@ import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -17,7 +18,8 @@ public class AdminDashboardController { private final AdminDashboardService adminDashboardService; - @GetMapping() + @GetMapping + @PreAuthorize("isAuthenticated() and hasRole('ADMIN')") public ResponseEntity> getAll() { DashBoardResponse response = adminDashboardService.getAll(); return ResponseEntity.ok( diff --git a/src/main/java/life/mosu/mosuserver/presentation/admin/AdminRecommendationController.java b/src/main/java/life/mosu/mosuserver/presentation/admin/AdminRecommendationController.java index ebc078dc..b7f344bd 100644 --- a/src/main/java/life/mosu/mosuserver/presentation/admin/AdminRecommendationController.java +++ b/src/main/java/life/mosu/mosuserver/presentation/admin/AdminRecommendationController.java @@ -5,6 +5,7 @@ import life.mosu.mosuserver.global.annotation.ExcelDownload; import life.mosu.mosuserver.presentation.admin.dto.RecommendationExcelDto; import lombok.RequiredArgsConstructor; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -22,9 +23,8 @@ public class AdminRecommendationController { fileName = "추천인 목록.xlsx", dtoClass = RecommendationExcelDto.class ) + @PreAuthorize("isAuthenticated() and hasRole('ADMIN')") public List downloadApplicationInfo() { return adminRecommendationService.getExcelData(); } - - } diff --git a/src/main/java/life/mosu/mosuserver/presentation/admin/AdminRefundController.java b/src/main/java/life/mosu/mosuserver/presentation/admin/AdminRefundController.java index 295cec7f..45efaea4 100644 --- a/src/main/java/life/mosu/mosuserver/presentation/admin/AdminRefundController.java +++ b/src/main/java/life/mosu/mosuserver/presentation/admin/AdminRefundController.java @@ -12,6 +12,7 @@ import org.springframework.data.web.PageableDefault; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -23,8 +24,8 @@ public class AdminRefundController { private final AdminRefundService adminRefundService; - @GetMapping() -// @PreAuthorize("isAuthenticated() and hasRole('ADMIN')") + @GetMapping + @PreAuthorize("isAuthenticated() and hasRole('ADMIN')") public ResponseEntity>> getAll( @PageableDefault(size = 15) Pageable pageable ) { @@ -33,13 +34,12 @@ public ResponseEntity>> getAll( ApiResponseWrapper.success(HttpStatus.OK, "환불 신청 수 조회 성공", responses)); } - @GetMapping(value = "/excel", produces = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") @ExcelDownload( fileName = "환불 목록.xlsx", dtoClass = RefundExcelDto.class ) -// @PreAuthorize("isAuthenticated() and hasRole('ADMIN')") + @PreAuthorize("isAuthenticated() and hasRole('ADMIN')") public List downloadRefundInfo() { return adminRefundService.getExcelData(); } diff --git a/src/main/java/life/mosu/mosuserver/presentation/admin/AdminStudentController.java b/src/main/java/life/mosu/mosuserver/presentation/admin/AdminStudentController.java index 7a048fc5..8a87eefa 100644 --- a/src/main/java/life/mosu/mosuserver/presentation/admin/AdminStudentController.java +++ b/src/main/java/life/mosu/mosuserver/presentation/admin/AdminStudentController.java @@ -14,6 +14,7 @@ import org.springframework.data.web.PageableDefault; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; @@ -27,7 +28,7 @@ public class AdminStudentController { private final AdminStudentService adminStudentService; @GetMapping() - //@PreAuthorize("isAuthenticated() and hasRole('ADMIN')") + @PreAuthorize("isAuthenticated() and hasRole('ADMIN')") public ResponseEntity>> getAll( @Valid @ModelAttribute StudentFilter filter, @PageableDefault(size = 10) Pageable pageable @@ -37,6 +38,7 @@ public ResponseEntity>> getAll( } @GetMapping("/excel") + @PreAuthorize("isAuthenticated() and hasRole('ADMIN')") @ExcelDownload( fileName = "학생 목록.xlsx", dtoClass = StudentExcelDto.class diff --git a/src/main/java/life/mosu/mosuserver/presentation/application/ApplicationController.java b/src/main/java/life/mosu/mosuserver/presentation/application/ApplicationController.java index 218e82af..41ac0d71 100644 --- a/src/main/java/life/mosu/mosuserver/presentation/application/ApplicationController.java +++ b/src/main/java/life/mosu/mosuserver/presentation/application/ApplicationController.java @@ -12,6 +12,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; @@ -29,7 +30,7 @@ public class ApplicationController implements ApplicationControllerDocs { private final ApplicationService applicationService; @PostMapping - // @PreAuthorize("isAuthenticated() and hasRole('USER')") + @PreAuthorize("isAuthenticated() and hasRole('USER')") public ResponseEntity> apply( @RequestParam Long userId, @Valid @RequestBody ApplicationRequest request, @@ -49,6 +50,7 @@ public ResponseEntity> apply( // TODO: 테스트 필요 //전체 신청 내역 조회 @GetMapping + @PreAuthorize("isAuthenticated() and hasRole('USER')") public ResponseEntity>> getApplications( @RequestParam Long userId ) { @@ -56,5 +58,4 @@ public ResponseEntity>> getApplicat return ResponseEntity.ok( ApiResponseWrapper.success(HttpStatus.OK, "신청 내역 조회 성공", responses)); } - } diff --git a/src/main/java/life/mosu/mosuserver/presentation/event/EventController.java b/src/main/java/life/mosu/mosuserver/presentation/event/EventController.java index 94800b6e..fa297e06 100644 --- a/src/main/java/life/mosu/mosuserver/presentation/event/EventController.java +++ b/src/main/java/life/mosu/mosuserver/presentation/event/EventController.java @@ -9,6 +9,7 @@ import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @@ -26,7 +27,7 @@ public class EventController implements EventControllerDocs { private final EventService eventService; @PostMapping - // @PreAuthorize("isAuthenticated() and hasRole('ADMIN')") + @PreAuthorize("isAuthenticated() and hasRole('ADMIN')") public ResponseEntity> createEvent( @Valid @RequestBody EventRequest request) { eventService.createEvent(request); @@ -49,7 +50,7 @@ public ResponseEntity> getEventDetail( } @PutMapping("/{eventId}") - // @PreAuthorize("isAuthenticated() and hasRole('ADMIN')") + @PreAuthorize("isAuthenticated() and hasRole('ADMIN')") public ResponseEntity> updateEvent( @PathVariable Long eventId, @Valid @RequestBody EventRequest request @@ -59,7 +60,7 @@ public ResponseEntity> updateEvent( } @DeleteMapping("/{eventId}") - // @PreAuthorize("isAuthenticated() and hasRole('ADMIN')") + @PreAuthorize("isAuthenticated() and hasRole('ADMIN')") public ResponseEntity> deleteEvent(@PathVariable Long eventId) { eventService.deleteEvent(eventId); return ResponseEntity.ok(ApiResponseWrapper.success(HttpStatus.OK, "이벤트 삭제 성공")); diff --git a/src/main/java/life/mosu/mosuserver/presentation/exam/ExamController.java b/src/main/java/life/mosu/mosuserver/presentation/exam/ExamController.java index 043473c9..94808547 100644 --- a/src/main/java/life/mosu/mosuserver/presentation/exam/ExamController.java +++ b/src/main/java/life/mosu/mosuserver/presentation/exam/ExamController.java @@ -8,6 +8,7 @@ import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; @@ -23,16 +24,17 @@ public class ExamController { private final ExamService examService; @PostMapping + @PreAuthorize("isAuthenticated()") public ResponseEntity> register( @RequestBody ExamRequest request ) { examService.register(request); return ResponseEntity.ok( ApiResponseWrapper.success(HttpStatus.CREATED, "시험 등록 성공")); - } @GetMapping("/all") + @PreAuthorize("isAuthenticated()") public ResponseEntity>> getExams() { List response = examService.getExams(); return ResponseEntity.ok( @@ -40,6 +42,7 @@ public ResponseEntity>> getExams() { } @GetMapping + @PreAuthorize("isAuthenticated()") public ResponseEntity>> getByArea( @RequestParam String areaName ) { @@ -49,6 +52,7 @@ public ResponseEntity>> getByArea( } @GetMapping("/areas") + @PreAuthorize("isAuthenticated()") public ResponseEntity>> getDistinctAreas() { List response = examService.getDistinctAreas(); return ResponseEntity.ok( diff --git a/src/main/java/life/mosu/mosuserver/presentation/examapplication/ExamApplicationController.java b/src/main/java/life/mosu/mosuserver/presentation/examapplication/ExamApplicationController.java index e2a2320d..a85600f8 100644 --- a/src/main/java/life/mosu/mosuserver/presentation/examapplication/ExamApplicationController.java +++ b/src/main/java/life/mosu/mosuserver/presentation/examapplication/ExamApplicationController.java @@ -1,6 +1,7 @@ package life.mosu.mosuserver.presentation.examapplication; import life.mosu.mosuserver.application.examapplication.ExamApplicationService; +import life.mosu.mosuserver.global.annotation.UserId; import life.mosu.mosuserver.global.util.ApiResponseWrapper; import life.mosu.mosuserver.presentation.admin.dto.ExamTicketResponse; import life.mosu.mosuserver.presentation.examapplication.dto.ExamApplicationInfoResponse; @@ -8,13 +9,13 @@ import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; 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.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController @@ -56,8 +57,9 @@ public ResponseEntity> updateSub } @GetMapping("{examApplicationId}/exam-ticket") + @PreAuthorize("isAuthenticated() and hasRole('USER')") public ResponseEntity> getExamTicket( - @RequestParam Long userId, + @UserId Long userId, @PathVariable("examApplicationId") Long examApplicationId ) { ExamTicketResponse response = examApplicationService.getExamTicket(examApplicationId); diff --git a/src/main/java/life/mosu/mosuserver/presentation/faq/FaqController.java b/src/main/java/life/mosu/mosuserver/presentation/faq/FaqController.java index 3dda92f4..e36dfe8f 100644 --- a/src/main/java/life/mosu/mosuserver/presentation/faq/FaqController.java +++ b/src/main/java/life/mosu/mosuserver/presentation/faq/FaqController.java @@ -10,6 +10,7 @@ import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @@ -28,9 +29,8 @@ public class FaqController { private final FaqService faqService; - //TODO: 관리자 권한 체크 추가 @PostMapping - // @PreAuthorize("isAuthenticated() and hasRole('ADMIN')") + @PreAuthorize("isAuthenticated() and hasRole('ADMIN')") public ResponseEntity> createFaq( @Valid @RequestBody FaqCreateRequest request) { faqService.createFaq(request); @@ -54,7 +54,7 @@ public ResponseEntity> getFaqDetail( } @PutMapping("/{faqId}") - // @PreAuthorize("isAuthenticated() and hasRole('ADMIN')") + @PreAuthorize("isAuthenticated() and hasRole('ADMIN')") public ResponseEntity> updateFaq( @PathVariable Long faqId, @Valid @RequestBody FaqUpdateRequest request @@ -63,9 +63,8 @@ public ResponseEntity> updateFaq( return ResponseEntity.ok(ApiResponseWrapper.success(HttpStatus.OK, "게시글 수정 성공")); } - //TODO: 관리자 권한 체크 추가 @DeleteMapping("/{faqId}") - // @PreAuthorize("isAuthenticated() and hasRole('ADMIN')") + @PreAuthorize("isAuthenticated() and hasRole('ADMIN')") public ResponseEntity> deleteFaq(@PathVariable Long faqId) { faqService.deleteFaq(faqId); return ResponseEntity.ok(ApiResponseWrapper.success(HttpStatus.OK, "게시글 삭제 성공")); diff --git a/src/main/java/life/mosu/mosuserver/presentation/inquiry/InquiryController.java b/src/main/java/life/mosu/mosuserver/presentation/inquiry/InquiryController.java index 64ea4450..26b0d314 100644 --- a/src/main/java/life/mosu/mosuserver/presentation/inquiry/InquiryController.java +++ b/src/main/java/life/mosu/mosuserver/presentation/inquiry/InquiryController.java @@ -16,6 +16,7 @@ import org.springframework.data.web.PageableDefault; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @@ -33,8 +34,9 @@ public class InquiryController implements InquiryControllerDocs { private final InquiryService inquiryService; private final InquiryAnswerService inquiryAnswerService; - + @PostMapping + public ResponseEntity> create( @RequestBody @Valid InquiryCreateRequest request) { inquiryService.createInquiry(request); @@ -42,6 +44,7 @@ public ResponseEntity> create( } @GetMapping("/list") + @PreAuthorize("isAuthenticated() and hasRole('USER')") public ResponseEntity>> getInquiryList( @RequestParam(required = false) InquiryStatus status, @RequestParam(required = false, defaultValue = "id") String sort, @@ -64,12 +67,14 @@ public ResponseEntity> getInquiryDetai } @DeleteMapping("/{postId}") + @PreAuthorize("isAuthenticated() and hasRole('USER')") public ResponseEntity> deleteInquiry(@PathVariable Long postId) { inquiryService.deleteInquiry(postId); return ResponseEntity.ok(ApiResponseWrapper.success(HttpStatus.OK, "질문 삭제 성공")); } @PostMapping("/{postId}/answer") + @PreAuthorize("isAuthenticated() and hasRole('ADMIN')") public ResponseEntity> inquiryAnswer( @PathVariable Long postId, @RequestBody InquiryAnswerRequest request) { @@ -78,6 +83,7 @@ public ResponseEntity> inquiryAnswer( } @PutMapping("/{postId}/answer") + @PreAuthorize("isAuthenticated() and hasRole('ADMIN')") public ResponseEntity> updateInquiryAnswer( @PathVariable Long postId, @RequestBody InquiryAnswerUpdateRequest request) { @@ -86,6 +92,7 @@ public ResponseEntity> updateInquiryAnswer( } @DeleteMapping("/{postId}/answer") + @PreAuthorize("isAuthenticated() and hasRole('ADMIN')") public ResponseEntity> deleteInquiryAnswer(@PathVariable Long postId) { inquiryAnswerService.deleteInquiryAnswer(postId); return ResponseEntity.ok(ApiResponseWrapper.success(HttpStatus.OK, "답변 삭제 성공")); diff --git a/src/main/java/life/mosu/mosuserver/presentation/payment/PaymentWidgetController.java b/src/main/java/life/mosu/mosuserver/presentation/payment/PaymentWidgetController.java index 4bfb20cc..ecfa8828 100644 --- a/src/main/java/life/mosu/mosuserver/presentation/payment/PaymentWidgetController.java +++ b/src/main/java/life/mosu/mosuserver/presentation/payment/PaymentWidgetController.java @@ -2,6 +2,7 @@ import jakarta.validation.Valid; import life.mosu.mosuserver.application.payment.PaymentService; +import life.mosu.mosuserver.global.annotation.UserId; import life.mosu.mosuserver.global.util.ApiResponseWrapper; import life.mosu.mosuserver.presentation.payment.dto.CancelPaymentRequest; import life.mosu.mosuserver.presentation.payment.dto.PaymentPrepareResponse; @@ -9,6 +10,7 @@ import life.mosu.mosuserver.presentation.payment.dto.PreparePaymentRequest; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; @@ -24,7 +26,9 @@ public class PaymentWidgetController { //TODO: 신청서 필요함. @PostMapping("/prepare") + @PreAuthorize("isAuthenticated() and hasRole('USER')") public ApiResponseWrapper prepare( + @UserId Long userId, @Valid @RequestBody PreparePaymentRequest request ) { PaymentPrepareResponse response = paymentService.prepare(request); @@ -38,13 +42,19 @@ public ApiResponseWrapper prepare( * @return */ @PostMapping("/confirm") - public ApiResponseWrapper confirm(@RequestBody PaymentRequest request) { + @PreAuthorize("isAuthenticated() and hasRole('USER')") + public ApiResponseWrapper confirm( + @UserId Long userId, + @RequestBody PaymentRequest request + ) { paymentService.confirm(request); return ApiResponseWrapper.success(HttpStatus.CREATED, "결제 승인 성공"); } @PostMapping("/{paymentId}/cancel") + @PreAuthorize("isAuthenticated() and hasRole('USER')") public ApiResponseWrapper cancel( + @UserId Long userId, @PathVariable String paymentId, @RequestBody CancelPaymentRequest request ) { diff --git a/src/main/java/life/mosu/mosuserver/presentation/profile/ProfileController.java b/src/main/java/life/mosu/mosuserver/presentation/profile/ProfileController.java index 73df1fd3..19ca1dcc 100644 --- a/src/main/java/life/mosu/mosuserver/presentation/profile/ProfileController.java +++ b/src/main/java/life/mosu/mosuserver/presentation/profile/ProfileController.java @@ -1,7 +1,6 @@ package life.mosu.mosuserver.presentation.profile; import jakarta.validation.Valid; -import life.mosu.mosuserver.application.auth.PrincipalDetails; import life.mosu.mosuserver.application.profile.ProfileService; import life.mosu.mosuserver.global.annotation.UserId; import life.mosu.mosuserver.global.util.ApiResponseWrapper; @@ -13,7 +12,6 @@ import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PutMapping; @@ -31,22 +29,22 @@ public class ProfileController implements ProfileControllerDocs { private final ProfileService profileService; @PostMapping + @PreAuthorize("isAuthenticated()") public ResponseEntity> create( - @AuthenticationPrincipal final PrincipalDetails principalDetails, + @UserId final Long userId, @Valid @RequestBody ProfileRequest request ) { - Long userId = principalDetails.getId(); log.info("userId: {}", userId); profileService.registerProfile(userId, request); return ResponseEntity.ok(ApiResponseWrapper.success(HttpStatus.CREATED, "프로필 등록 성공")); } @PutMapping + @PreAuthorize("isAuthenticated()") public ResponseEntity> update( - @AuthenticationPrincipal final PrincipalDetails principalDetails, + @UserId final Long userId, @Valid @RequestBody EditProfileRequest request ) { - Long userId = principalDetails.getId(); log.info("userId: {}", userId); profileService.editProfile(userId, request); return ResponseEntity.ok(ApiResponseWrapper.success(HttpStatus.OK, "프로필 수정 성공")); diff --git a/src/main/java/life/mosu/mosuserver/presentation/profile/ProfileControllerDocs.java b/src/main/java/life/mosu/mosuserver/presentation/profile/ProfileControllerDocs.java index c879424c..fb09438a 100644 --- a/src/main/java/life/mosu/mosuserver/presentation/profile/ProfileControllerDocs.java +++ b/src/main/java/life/mosu/mosuserver/presentation/profile/ProfileControllerDocs.java @@ -9,13 +9,12 @@ import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; -import life.mosu.mosuserver.application.auth.PrincipalDetails; +import life.mosu.mosuserver.global.annotation.UserId; import life.mosu.mosuserver.global.util.ApiResponseWrapper; import life.mosu.mosuserver.presentation.profile.dto.EditProfileRequest; import life.mosu.mosuserver.presentation.profile.dto.ProfileDetailResponse; import life.mosu.mosuserver.presentation.profile.dto.ProfileRequest; import org.springframework.http.ResponseEntity; -import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestParam; @@ -27,7 +26,7 @@ public interface ProfileControllerDocs { @ApiResponse(responseCode = "201", description = "프로필 등록 성공") }) ResponseEntity> create( - @AuthenticationPrincipal final PrincipalDetails principalDetails, + @UserId final Long userId, @Valid @RequestBody ProfileRequest request ); @@ -36,7 +35,7 @@ ResponseEntity> create( @ApiResponse(responseCode = "200", description = "프로필 수정 성공") }) ResponseEntity> update( - @AuthenticationPrincipal final PrincipalDetails principalDetails, + @UserId final Long userId, @Parameter(description = "프로필 수정 요청 정보", required = true) @Valid @RequestBody EditProfileRequest request diff --git a/src/main/java/life/mosu/mosuserver/presentation/profile/RecommenderController.java b/src/main/java/life/mosu/mosuserver/presentation/profile/RecommenderController.java index 0c327ed1..81683f42 100644 --- a/src/main/java/life/mosu/mosuserver/presentation/profile/RecommenderController.java +++ b/src/main/java/life/mosu/mosuserver/presentation/profile/RecommenderController.java @@ -2,16 +2,17 @@ import jakarta.validation.Valid; import life.mosu.mosuserver.application.profile.RecommenderService; +import life.mosu.mosuserver.global.annotation.UserId; import life.mosu.mosuserver.global.util.ApiResponseWrapper; import life.mosu.mosuserver.presentation.profile.dto.RecommenderRegistrationRequest; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController @@ -23,8 +24,9 @@ public class RecommenderController implements RecommenderControllerDocs { @Override @PostMapping + @PreAuthorize("isAuthenticated()") public ResponseEntity> register( - @RequestParam Long userId, + @UserId Long userId, @Valid @RequestBody RecommenderRegistrationRequest request) { recommenderService.registerRecommender(userId, request); return ResponseEntity.status(HttpStatus.CREATED) @@ -33,8 +35,9 @@ public ResponseEntity> register( @Override @GetMapping("/verify") + @PreAuthorize("isAuthenticated()") public ResponseEntity> verify( - @RequestParam Long userId) { + @UserId Long userId) { Boolean isRegistered = recommenderService.verifyRecommender(userId); if (isRegistered) { diff --git a/src/main/java/life/mosu/mosuserver/presentation/recommendation/RecommendationController.java b/src/main/java/life/mosu/mosuserver/presentation/recommendation/RecommendationController.java index 211df921..483da9ce 100644 --- a/src/main/java/life/mosu/mosuserver/presentation/recommendation/RecommendationController.java +++ b/src/main/java/life/mosu/mosuserver/presentation/recommendation/RecommendationController.java @@ -2,16 +2,17 @@ import jakarta.validation.Valid; import life.mosu.mosuserver.application.recommendation.RecommendationService; +import life.mosu.mosuserver.global.annotation.UserId; import life.mosu.mosuserver.global.util.ApiResponseWrapper; import life.mosu.mosuserver.presentation.recommendation.dto.RecommendationRequest; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @Slf4j @@ -23,8 +24,9 @@ public class RecommendationController { private final RecommendationService recommendationService; @PostMapping + @PreAuthorize("isAuthenticated() and hasRole('USER')") public ResponseEntity> create( - @RequestParam Long userId, + @UserId Long userId, @Valid @RequestBody RecommendationRequest request ) { recommendationService.create(userId, request);