diff --git a/src/main/java/com/kamco/cd/kamcoback/config/SecurityConfig.java b/src/main/java/com/kamco/cd/kamcoback/config/SecurityConfig.java index fe1ab0cf..bf45341b 100644 --- a/src/main/java/com/kamco/cd/kamcoback/config/SecurityConfig.java +++ b/src/main/java/com/kamco/cd/kamcoback/config/SecurityConfig.java @@ -77,8 +77,12 @@ public class SecurityConfig { "/api/members/*/password", "/v3/api-docs/**") .permitAll() + // 로그인한 사용자만 가능 + .requestMatchers("/api/user/**") + .authenticated() .anyRequest() // .access(redisAuthorizationManager) + .authenticated()) .addFilterBefore( jwtAuthenticationFilter, diff --git a/src/main/java/com/kamco/cd/kamcoback/members/dto/MembersDto.java b/src/main/java/com/kamco/cd/kamcoback/members/dto/MembersDto.java index b03b08cd..8af2bb91 100644 --- a/src/main/java/com/kamco/cd/kamcoback/members/dto/MembersDto.java +++ b/src/main/java/com/kamco/cd/kamcoback/members/dto/MembersDto.java @@ -1,5 +1,6 @@ package com.kamco.cd.kamcoback.members.dto; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.kamco.cd.kamcoback.common.enums.RoleType; import com.kamco.cd.kamcoback.common.enums.StatusType; import com.kamco.cd.kamcoback.common.utils.enums.Enums; @@ -181,4 +182,84 @@ public class MembersDto { private String employeeNo; private String role; } + + @Getter + public static class RoleEntity { + + private final RoleType type; + private final String name; + + public RoleEntity(RoleType status) { + this.type = status; + this.name = status.getText(); + } + } + + @Getter + public static class StatusEntity { + + private final StatusType type; + private final String name; + + public StatusEntity(StatusType status) { + this.type = status; + this.name = status.getText(); + } + } + + @Getter + public static class EntityData { + + @JsonIgnore private Long id; + private UUID uuid; + private String name; + private String employeeNo; + private RoleEntity role; + private StatusEntity status; + @JsonFormatDttm private ZonedDateTime createdDttm; + @JsonFormatDttm private ZonedDateTime firstLoginDttm; + @JsonFormatDttm private ZonedDateTime lastLoginDttm; + @JsonFormatDttm private ZonedDateTime statusChgDttm; + + private Boolean isReset; + + public EntityData( + Long id, + UUID uuid, + RoleType role, + String name, + String employeeNo, + StatusType status, + ZonedDateTime createdDttm, + ZonedDateTime firstLoginDttm, + ZonedDateTime lastLoginDttm, + ZonedDateTime statusChgDttm, + Boolean isReset) { + this.id = id; + this.uuid = uuid; + this.name = name; + this.employeeNo = employeeNo; + this.status = new StatusEntity(status); + this.createdDttm = createdDttm; + this.firstLoginDttm = firstLoginDttm; + this.lastLoginDttm = lastLoginDttm; + this.statusChgDttm = statusChgDttm; + this.isReset = isReset; + this.role = new RoleEntity(role); + } + + private String getUserRoleName(String roleId) { + RoleType type = Enums.fromId(RoleType.class, roleId); + return type.getText(); + } + + private String getStatusName(String status, Boolean pwdResetYn) { + StatusType type = Enums.fromId(StatusType.class, status); + pwdResetYn = pwdResetYn != null && pwdResetYn; + if (type.equals(StatusType.PENDING) && pwdResetYn) { + type = StatusType.ACTIVE; + } + return type.getText(); + } + } } diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/core/MembersCoreService.java b/src/main/java/com/kamco/cd/kamcoback/postgres/core/MembersCoreService.java index cb040aa6..1aa36339 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/core/MembersCoreService.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/core/MembersCoreService.java @@ -23,6 +23,7 @@ import org.mindrot.jbcrypt.BCrypt; import org.springframework.data.domain.Page; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; @Service @RequiredArgsConstructor @@ -173,4 +174,18 @@ public class MembersCoreService { public boolean existsByEmployeeNo(String employeeNo) { return membersRepository.existsByEmployeeNo(employeeNo); } + + /** + * 회원정보 조회 (단건 ) by uuid + * + * @param uuid + */ + @Transactional(readOnly = true) + public MembersDto.EntityData getUserInfoByUuid(String memberUuid) { + MemberEntity member = + membersRepository + .findByUUID(UUID.fromString(memberUuid)) + .orElseThrow(MemberNotFoundException::new); + return member.toEntity(); + } } diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MemberEntity.java b/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MemberEntity.java index d2088ad9..1d97dd2c 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MemberEntity.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MemberEntity.java @@ -1,6 +1,8 @@ package com.kamco.cd.kamcoback.postgres.entity; +import com.kamco.cd.kamcoback.common.enums.RoleType; import com.kamco.cd.kamcoback.common.enums.StatusType; +import com.kamco.cd.kamcoback.members.dto.MembersDto.EntityData; import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; @@ -14,8 +16,10 @@ import java.util.Objects; import java.util.UUID; import lombok.Getter; import lombok.Setter; +import lombok.extern.slf4j.Slf4j; import org.hibernate.annotations.ColumnDefault; +@Slf4j @Getter @Setter @Entity @@ -100,4 +104,19 @@ public class MemberEntity { this.status = newStatus; this.statusChgDttm = ZonedDateTime.now(); } + + public EntityData toEntity() { + return new EntityData( + id, + uuid, + RoleType.valueOf(userRole), + name, + employeeNo, + StatusType.valueOf(status), + createdDttm, + firstLoginDttm, + lastLoginDttm, + statusChgDttm, + pwdResetYn); + } } diff --git a/src/main/java/com/kamco/cd/kamcoback/user/UserApiController.java b/src/main/java/com/kamco/cd/kamcoback/user/UserApiController.java new file mode 100644 index 00000000..c9d30696 --- /dev/null +++ b/src/main/java/com/kamco/cd/kamcoback/user/UserApiController.java @@ -0,0 +1,53 @@ +package com.kamco.cd.kamcoback.user; + +import com.kamco.cd.kamcoback.config.api.ApiResponseDto; +import com.kamco.cd.kamcoback.members.dto.MembersDto; +import com.kamco.cd.kamcoback.user.service.UserInfoService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@Tag(name = "사용자 정보", description = "사용자 정보 조회 API") +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/user") +public class UserApiController { + + private final UserInfoService userInfoService; + + @Operation( + summary = "현재 로그인 사용자 정보 조회", + description = "JWT 토큰에서 사용자 ID를 추출하여 현재 로그인한 사용자의 정보를 조회합니다.") + @ApiResponses( + value = { + @ApiResponse( + responseCode = "200", + description = "조회 성공", + content = + @Content( + mediaType = "application/json", + schema = @Schema(implementation = MembersDto.EntityData.class))), + @ApiResponse( + responseCode = "401", + description = "인증 실패 (토큰 없음 또는 유효하지 않음)", + content = @Content), + @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) + }) + @GetMapping("/iam") + public ApiResponseDto iam() { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + String memberUuid = authentication.getName(); // JWT의 sub 값 (사용자 ID) + + // Member의 정보를 조회해서 리턴한다. + return ApiResponseDto.createOK(userInfoService.getUserInfoByUuid(memberUuid)); + } +} diff --git a/src/main/java/com/kamco/cd/kamcoback/user/service/UserInfoService.java b/src/main/java/com/kamco/cd/kamcoback/user/service/UserInfoService.java new file mode 100644 index 00000000..2d93153a --- /dev/null +++ b/src/main/java/com/kamco/cd/kamcoback/user/service/UserInfoService.java @@ -0,0 +1,26 @@ +package com.kamco.cd.kamcoback.user.service; + +import com.kamco.cd.kamcoback.members.dto.MembersDto; +import com.kamco.cd.kamcoback.postgres.core.MembersCoreService; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@RequiredArgsConstructor +@Service +@Transactional(readOnly = true) +public class UserInfoService { + + private final MembersCoreService membersCoreService; + + /** + * 회원정보 조회 (단건 ) by uuid + * + * @param uuid + * @return + */ + public MembersDto.EntityData getUserInfoByUuid(@NotNull String uuid) { + return membersCoreService.getUserInfoByUuid(uuid); + } +}