From 6dff187402edaa975fc097b64f2853b554ad0db4 Mon Sep 17 00:00:00 2001 From: sangeun Date: Wed, 22 May 2024 19:58:17 +0900 Subject: [PATCH] =?UTF-8?q?fix=20:=20jwt=20=ED=86=A0=ED=81=B0=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EC=9C=A0=EC=A0=80=20=EC=A0=95=EB=B3=B4=20=EA=B0=80?= =?UTF-8?q?=EC=A0=B8=EC=98=A4=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../activity/api/ActivityController.java | 17 +++++++++--- .../domain/record/api/RecordController.java | 22 +++++++++++---- .../domain/user/api/UserController.java | 23 +++++----------- .../user/application/UserFindService.java | 5 ++++ .../user/repository/UserRepository.java | 1 + .../global/auth/JwtTokenProvider.java | 27 +++++-------------- 6 files changed, 50 insertions(+), 45 deletions(-) diff --git a/src/main/java/com/hobak/happinessql/domain/activity/api/ActivityController.java b/src/main/java/com/hobak/happinessql/domain/activity/api/ActivityController.java index 62a277e..474d8f8 100644 --- a/src/main/java/com/hobak/happinessql/domain/activity/api/ActivityController.java +++ b/src/main/java/com/hobak/happinessql/domain/activity/api/ActivityController.java @@ -3,10 +3,14 @@ import com.hobak.happinessql.domain.activity.application.*; import com.hobak.happinessql.domain.activity.converter.ActivityConverter; import com.hobak.happinessql.domain.activity.dto.*; +import com.hobak.happinessql.domain.user.application.UserFindService; +import com.hobak.happinessql.domain.user.domain.User; import com.hobak.happinessql.global.response.DataResponseDto; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.security.core.userdetails.UserDetails; import org.springframework.web.bind.annotation.*; @Tag(name="Activity", description = "활동 관련 REST API에 대한 명세를 제공합니다.") @@ -20,17 +24,22 @@ public class ActivityController { private final ActivityDeleteService activityDeleteService; private final ActivityUpdateService activityUpdateService; private final ActivitySearchService activitySearchService; + private final UserFindService userFindService; @Operation(summary = "활동 리스트 조회", description = "유저가 가지고 있는 활동 목록을 조회합니다. 행복 기록 생성 시 활동 선택 창에서 사용하는 API입니다.") @GetMapping - public DataResponseDto getActivities(@RequestParam Long userId) { + public DataResponseDto getActivities(@AuthenticationPrincipal UserDetails userDetails) { + User user = userFindService.findByUserDetails(userDetails); + Long userId = user.getUserId(); ActivityListResponseDto response = activityListService.getActivities(userId); return DataResponseDto.of(response, "사용자의 모든 카테고리별 활동을 성공적으로 조회했습니다."); } @Operation(summary = "활동 추가", description = "기타 카테고리에 활동을 추가합니다.") @PostMapping - public DataResponseDto createActivity(@RequestBody ActivityCreateRequestDto requestDto, @RequestParam Long userId){ + public DataResponseDto createActivity(@RequestBody ActivityCreateRequestDto requestDto, @AuthenticationPrincipal UserDetails userDetails){ + User user = userFindService.findByUserDetails(userDetails); + Long userId = user.getUserId(); ActivityResponseDto responseDto = activityCreateService.createActivity(requestDto,userId); return DataResponseDto.of(responseDto,"활동을 성공적으로 추가했습니다."); } @@ -52,7 +61,9 @@ public DataResponseDto updateActicity(@PathVariable L @Operation(summary = "활동 검색", description = "유저가 갖고 있는 활동을 검색합니다. (활동의 description에 있는 내용은 아직 검색되지 않습니다.)") @PostMapping("/search") - public DataResponseDto searchActivities(@RequestBody ActivitySearchRequestDto requestDto, @RequestParam Long userId) { + public DataResponseDto searchActivities(@RequestBody ActivitySearchRequestDto requestDto, @AuthenticationPrincipal UserDetails userDetails) { + User user = userFindService.findByUserDetails(userDetails); + Long userId = user.getUserId(); ActivitySearchResponseDto responseDto = activitySearchService.searchActivities(requestDto.getSearch(), userId); return DataResponseDto.of(responseDto, "활동을 성공적으로 검색했습니다."); } diff --git a/src/main/java/com/hobak/happinessql/domain/record/api/RecordController.java b/src/main/java/com/hobak/happinessql/domain/record/api/RecordController.java index 13bcffc..3d745bd 100644 --- a/src/main/java/com/hobak/happinessql/domain/record/api/RecordController.java +++ b/src/main/java/com/hobak/happinessql/domain/record/api/RecordController.java @@ -11,6 +11,8 @@ import com.hobak.happinessql.domain.record.dto.RecordCreateRequestDto; import com.hobak.happinessql.domain.record.dto.RecordCreateResponseDto; import com.hobak.happinessql.domain.record.dto.RecordResponseDto; +import com.hobak.happinessql.domain.user.application.UserFindService; +import com.hobak.happinessql.domain.user.domain.User; import com.hobak.happinessql.global.response.DataResponseDto; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; @@ -18,6 +20,8 @@ import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.http.MediaType; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.security.core.userdetails.UserDetails; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; @@ -33,15 +37,17 @@ public class RecordController { private final RecordPagingService recordPagingService; private final RecordCalendarListService recordCalendarListService; private final RecordCalendarDetailService recordCalendarDetailService; + private final UserFindService userFindService; @Operation(summary = "행복 기록 추가", description = "행복 기록을 생성합니다.") @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE) public DataResponseDto createRecord( @Valid @RequestPart(value="content") RecordCreateRequestDto requestDto, @RequestPart(required = false) MultipartFile img, - Long userId + @AuthenticationPrincipal UserDetails userDetails ) { - + User user = userFindService.findByUserDetails(userDetails); + Long userId = user.getUserId(); Long recordId = recordCreateService.createRecord(userId, requestDto, img); RecordCreateResponseDto recordCreationResponseDto = RecordConverter.toRecordCreateResponseDto(recordId); @@ -53,7 +59,9 @@ public DataResponseDto createRecord( @Parameter(name="size", description = "한 번에 가져올 레코드의 개수") }) @GetMapping - public DataResponseDto> getRecordList(@RequestParam(required = false) Long lastRecordId, @RequestParam int size, Long userId) { + public DataResponseDto> getRecordList(@RequestParam(required = false) Long lastRecordId, @RequestParam int size, @AuthenticationPrincipal UserDetails userDetails) { + User user = userFindService.findByUserDetails(userDetails); + Long userId = user.getUserId(); List responseDtos = recordPagingService.fetchRecordPagesBy(lastRecordId, size, userId); return DataResponseDto.of(responseDtos, "행복 기록을 성공적으로 조회했습니다."); } @@ -63,7 +71,9 @@ public DataResponseDto> getRecordList(@RequestParam(requ @Parameter(name="month", description = "month를 지정하지 않으면 오늘 날짜 기준으로 자동 설정됩니다.") }) @GetMapping("/calendar") - public DataResponseDto> getRecordCalenderList(@RequestParam(required = false) Integer month, @RequestParam(required = false) Integer year, @RequestParam Long userId) { + public DataResponseDto> getRecordCalenderList(@RequestParam(required = false) Integer month, @RequestParam(required = false) Integer year, @AuthenticationPrincipal UserDetails userDetails) { + User user = userFindService.findByUserDetails(userDetails); + Long userId = user.getUserId(); List responseDtos = recordCalendarListService.getHappinessAverages(month, year, userId); return DataResponseDto.of(responseDtos, "행복 달력을 성공적으로 조회했습니다."); } @@ -72,7 +82,9 @@ public DataResponseDto> getRecordCalenderList(@R parameters = {@Parameter(name="date", description = "format : yyyy-mm-dd") }) @GetMapping("/calendar/{date}") - public DataResponseDto> getRecordCalenderList(@PathVariable String date, @RequestParam Long userId) { + public DataResponseDto> getRecordCalenderList(@PathVariable String date, @AuthenticationPrincipal UserDetails userDetails) { + User user = userFindService.findByUserDetails(userDetails); + Long userId = user.getUserId(); List responseDtos = recordCalendarDetailService.getRecords(date, userId); return DataResponseDto.of(responseDtos, "행복 달력을 성공적으로 조회했습니다."); } diff --git a/src/main/java/com/hobak/happinessql/domain/user/api/UserController.java b/src/main/java/com/hobak/happinessql/domain/user/api/UserController.java index dad6905..be51271 100644 --- a/src/main/java/com/hobak/happinessql/domain/user/api/UserController.java +++ b/src/main/java/com/hobak/happinessql/domain/user/api/UserController.java @@ -14,6 +14,7 @@ import lombok.NonNull; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.web.bind.annotation.*; @@ -23,29 +24,24 @@ @RequestMapping("api/users") public class UserController { - private final UserFindService userFindService; private final UserProfileService userProfileService; private final UserService userService; private final CustomUserDetailsService customUserDetailsService; + private final CategoryCreateService categoryCreateService; + private final UserFindService userFindService; @NonNull private PasswordEncoder passwordEncoder; @GetMapping("/profile") - public DataResponseDto getUserInfo() { - // TODO : 임시값 -> 로그인한 유저의 id를 찾아내는 로직으로 변경 - Long userId = 1L; - - User user = userFindService.findUserById(userId); + public DataResponseDto getUserInfo(@AuthenticationPrincipal UserDetails userDetails) { + User user = userFindService.findByUserDetails(userDetails); UserInfoResponseDto userInfoResponseDto = UserConverter.toUserInfoResponseDto(user); - return DataResponseDto.of(userInfoResponseDto, "유저 프로필을 성공적으로 조회했습니다."); } @PutMapping("/profile") - public DataResponseDto updateUserInfo(@RequestBody @Valid UserProfileUpdateRequestDto requestDto) { - Long userId = 1L; - - User user = userFindService.findUserById(userId); + public DataResponseDto updateUserInfo(@RequestBody @Valid UserProfileUpdateRequestDto requestDto, @AuthenticationPrincipal UserDetails userDetails) { + User user = userFindService.findByUserDetails(userDetails); User updatedUser = userProfileService.updateUserProfile(user, requestDto); UserInfoResponseDto responseDto = UserConverter.toUserInfoResponseDto(updatedUser); @@ -62,11 +58,6 @@ public DataResponseDto signIn(@RequestBody SignInDto signInDto) { } - @PostMapping("/test") - public String test(){ - return "success"; - } - private final CategoryCreateService categoryCreateService; @PostMapping("/sign-up") public DataResponseDto signUp(@RequestBody SignUpDto signUpDto){ UserDto savedUserDto = userService.signUp(signUpDto); diff --git a/src/main/java/com/hobak/happinessql/domain/user/application/UserFindService.java b/src/main/java/com/hobak/happinessql/domain/user/application/UserFindService.java index 3923ad8..0230bf4 100644 --- a/src/main/java/com/hobak/happinessql/domain/user/application/UserFindService.java +++ b/src/main/java/com/hobak/happinessql/domain/user/application/UserFindService.java @@ -4,6 +4,7 @@ import com.hobak.happinessql.domain.user.exception.UserNotFoundException; import com.hobak.happinessql.domain.user.repository.UserRepository; import lombok.RequiredArgsConstructor; +import org.springframework.security.core.userdetails.UserDetails; import org.springframework.stereotype.Service; @Service @@ -16,4 +17,8 @@ public User findUserById(Long userId) { return userRespository.findById(userId) .orElseThrow(() -> new UserNotFoundException("User with ID" + userId)); } + + public User findByUserDetails(UserDetails userDetails){ + return userRespository.findUserByusername(userDetails.getUsername()); + } } diff --git a/src/main/java/com/hobak/happinessql/domain/user/repository/UserRepository.java b/src/main/java/com/hobak/happinessql/domain/user/repository/UserRepository.java index f94c1d1..15ecb4e 100644 --- a/src/main/java/com/hobak/happinessql/domain/user/repository/UserRepository.java +++ b/src/main/java/com/hobak/happinessql/domain/user/repository/UserRepository.java @@ -9,4 +9,5 @@ public interface UserRepository extends JpaRepository { Optional findByUsername(String username); Boolean existsByUsername(String username); + User findUserByusername(String username); } diff --git a/src/main/java/com/hobak/happinessql/global/auth/JwtTokenProvider.java b/src/main/java/com/hobak/happinessql/global/auth/JwtTokenProvider.java index acae74e..cf75114 100644 --- a/src/main/java/com/hobak/happinessql/global/auth/JwtTokenProvider.java +++ b/src/main/java/com/hobak/happinessql/global/auth/JwtTokenProvider.java @@ -1,5 +1,6 @@ package com.hobak.happinessql.global.auth; +import com.hobak.happinessql.domain.user.application.*; import io.jsonwebtoken.*; import io.jsonwebtoken.io.Decoders; import io.jsonwebtoken.security.Keys; @@ -8,14 +9,9 @@ import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.authority.SimpleGrantedAuthority; -import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.stereotype.Component; - import java.security.Key; -import java.util.Arrays; -import java.util.Collection; import java.util.Date; import java.util.stream.Collectors; @@ -23,9 +19,11 @@ @Component public class JwtTokenProvider { private final Key key; - public JwtTokenProvider(@Value("${jwt.secret}")String secretKey){ + private final CustomUserDetailsService customUserDetailsService; + public JwtTokenProvider(@Value("${jwt.secret}")String secretKey, CustomUserDetailsService customUserDetailsService){ byte[] keyBytes = Decoders.BASE64.decode(secretKey); this.key = Keys.hmacShaKeyFor(keyBytes); + this.customUserDetailsService = customUserDetailsService; } // Member 정보를 가지고 AccessToken, RefreshToken을 생성하는 메서드 public JwtToken generateToken(Authentication authentication) { @@ -60,22 +58,9 @@ public JwtToken generateToken(Authentication authentication) { // Jwt 토큰을 복호화하여 토큰에 들어있는 정보를 꺼내는 메서드 public Authentication getAuthentication(String accessToken) { - // Jwt 토큰 복호화 Claims claims = parseClaims(accessToken); - - if (claims.get("auth") == null) { - throw new RuntimeException("권한 정보가 없는 토큰입니다."); - } - - // 클레임에서 권한 정보 가져오기 - Collection authorities = Arrays.stream(claims.get("auth").toString().split(",")) - .map(SimpleGrantedAuthority::new) - .collect(Collectors.toList()); - - // UserDetails 객체를 만들어서 Authentication return - // UserDetails: interface, User: UserDetails를 구현한 class - UserDetails principal = new User(claims.getSubject(), "", authorities); - return new UsernamePasswordAuthenticationToken(principal, "", authorities); + UserDetails userDetails = customUserDetailsService.loadUserByUsername(claims.getSubject()); + return new UsernamePasswordAuthenticationToken(userDetails, accessToken, userDetails.getAuthorities()); } // 토큰 정보를 검증하는 메서드