diff --git a/src/main/java/store/itpick/backend/controller/UserController.java b/src/main/java/store/itpick/backend/controller/UserController.java index f109658..f1c81d0 100644 --- a/src/main/java/store/itpick/backend/controller/UserController.java +++ b/src/main/java/store/itpick/backend/controller/UserController.java @@ -1,17 +1,31 @@ package store.itpick.backend.controller; +import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.validation.BindingResult; +import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import store.itpick.backend.common.response.BaseResponse; +import store.itpick.backend.dto.auth.LoginRequest; +import store.itpick.backend.dto.auth.LoginResponse; import store.itpick.backend.dto.user.user.PostUserRequest; import store.itpick.backend.dto.user.user.PostUserResponse; +import store.itpick.backend.jwt.JwtProvider; +import store.itpick.backend.model.User; import store.itpick.backend.service.UserService; import store.itpick.backend.common.exception.UserException; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + import static store.itpick.backend.common.response.status.BaseExceptionResponseStatus.INVALID_USER_VALUE; import static store.itpick.backend.util.BindingResultUtils.getErrorMessages; @@ -23,6 +37,27 @@ public class UserController { @Autowired private final UserService userService; + @Autowired + private JwtProvider jwtProvider; + + + /** + * 로그인 + */ + @PostMapping("/login") + public BaseResponse login(@Validated @RequestBody LoginRequest authRequest, BindingResult bindingResult) { + log.info("[AuthController.login]"); + if (bindingResult.hasErrors()) { + throw new UserException(INVALID_USER_VALUE, getErrorMessages(bindingResult)); + } + return new BaseResponse<>(userService.login(authRequest)); + } + + @PostMapping("/logout") + public BaseResponse logoutUser() { + return new BaseResponse<>(null); + } + @PostMapping("/signup") public BaseResponse signUp(@RequestBody PostUserRequest postUserRequest, BindingResult bindingResult) { diff --git a/src/main/java/store/itpick/backend/dto/user/user/PostUserRequest.java b/src/main/java/store/itpick/backend/dto/user/user/PostUserRequest.java index 0d2941c..42d54d8 100644 --- a/src/main/java/store/itpick/backend/dto/user/user/PostUserRequest.java +++ b/src/main/java/store/itpick/backend/dto/user/user/PostUserRequest.java @@ -35,5 +35,5 @@ public class PostUserRequest { @NotBlank(message = "birth_date: 필수입니다.") - private Long birth_date; + private String birth_date; } diff --git a/src/main/java/store/itpick/backend/model/LikedTopic.java b/src/main/java/store/itpick/backend/model/LikedTopic.java new file mode 100644 index 0000000..4a3196f --- /dev/null +++ b/src/main/java/store/itpick/backend/model/LikedTopic.java @@ -0,0 +1,28 @@ +package store.itpick.backend.model; + +import jakarta.persistence.*; + +import java.sql.Timestamp; + +@Entity +@Table(name = "liked_topic") +public class LikedTopic { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "liked_topic_id") + private Long likedTopicId; + + @Column(name = "status", nullable = false, length = 20) + private String status; + + @Column(name = "create_at", nullable = false) + private Timestamp createAt; + + @Column(name = "update_at") + private Timestamp updateAt; + + @ManyToOne + @JoinColumn(name = "user_id", nullable = false) + private User user; +} diff --git a/src/main/java/store/itpick/backend/model/TermAgreement.java b/src/main/java/store/itpick/backend/model/TermAgreement.java new file mode 100644 index 0000000..bcbdae0 --- /dev/null +++ b/src/main/java/store/itpick/backend/model/TermAgreement.java @@ -0,0 +1,33 @@ +package store.itpick.backend.model; + +import jakarta.persistence.*; + +import java.sql.Timestamp; + +@Entity +@Table(name = "term_agreement") +public class TermAgreement { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "agreement_id") + private Long agreementId; + + @Column(name = "status", nullable = false, length = 10) + private String status; + + @Column(name = "update_at", nullable = false) + private Timestamp updateAt; + + @Column(name = "created_at", nullable = false) + private Timestamp createdAt; + + @Column(name = "agreement_type") + private int agreementType; + + @ManyToOne + @JoinColumn(name = "user_id", nullable = false) + private User user; + +} + diff --git a/src/main/java/store/itpick/backend/model/User.java b/src/main/java/store/itpick/backend/model/User.java index 5f5d8e7..ee43775 100644 --- a/src/main/java/store/itpick/backend/model/User.java +++ b/src/main/java/store/itpick/backend/model/User.java @@ -1,12 +1,10 @@ package store.itpick.backend.model; import jakarta.persistence.*; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; +import lombok.*; -import java.security.Timestamp; +import java.sql.Timestamp; +import java.util.List; @Entity @Table(name = "users") @@ -14,43 +12,49 @@ @NoArgsConstructor @AllArgsConstructor @Builder +@Getter public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "user_id") - private long id; + private Long userId; - @Column(nullable = false) + @Column(name = "email", nullable = false, length = 50) private String email; - @Column(nullable = false) + @Column(name = "password", nullable = false, length = 200) private String password; - @Column(nullable = false) - + @Column(name = "nickname", nullable = false, length = 20) private String nickname; - @Column(nullable = false) - private Long birth_date; + @Column(name = "birth_date", nullable = false, length = 20) + private String birthDate; - @Column - private Boolean alert_setting; + @Column(name = "alert_setting", nullable = false) + private boolean alertSetting; - @Column - private String reference_code; + @Column(name = "reference_code", length = 50) + private String referenceCode; - @Column - private String image_url; + @Column(name = "image_url", columnDefinition = "TEXT") + private String imageUrl; - @Column - private String refresh_token; + @Column(name = "refresh_token", columnDefinition = "TEXT") + private String refreshToken; - @Column + @Column(name = "status", nullable = false, length = 20) private String status; - @Column - private Timestamp create_at; + @Column(name = "create_at", nullable = false) + private java.sql.Timestamp createAt; + + @Column(name = "update_at") + private Timestamp updateAt; + + @OneToMany(mappedBy = "user") + private List likedTopics; - @Column - private Timestamp update_at; + @OneToMany(mappedBy = "user") + private List termAgreements; } diff --git a/src/main/java/store/itpick/backend/repository/UserRepository.java b/src/main/java/store/itpick/backend/repository/UserRepository.java index 805070e..bcab275 100644 --- a/src/main/java/store/itpick/backend/repository/UserRepository.java +++ b/src/main/java/store/itpick/backend/repository/UserRepository.java @@ -5,6 +5,7 @@ import store.itpick.backend.model.User; import java.util.List; +import java.util.Optional; @Repository public interface UserRepository extends JpaRepository { @@ -12,4 +13,8 @@ public interface UserRepository extends JpaRepository { boolean existsByEmailAndStatusIn(String email, List status); boolean existsByNicknameAndStatusIn(String nickname, List status); + + Optional getUserByEmail(String email); + Optional getUserByUserId(Long userId); + } diff --git a/src/main/java/store/itpick/backend/service/UserService.java b/src/main/java/store/itpick/backend/service/UserService.java index 10a4f9b..089f579 100644 --- a/src/main/java/store/itpick/backend/service/UserService.java +++ b/src/main/java/store/itpick/backend/service/UserService.java @@ -1,13 +1,18 @@ package store.itpick.backend.service; import lombok.RequiredArgsConstructor; +import org.springframework.dao.IncorrectResultSizeDataAccessException; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import store.itpick.backend.common.exception.UserException; import store.itpick.backend.common.response.status.BaseExceptionResponseStatus; +import store.itpick.backend.dto.auth.LoginRequest; +import store.itpick.backend.dto.auth.LoginResponse; import store.itpick.backend.dto.user.user.PostUserRequest; import store.itpick.backend.dto.user.user.PostUserResponse; +import store.itpick.backend.jwt.JwtProvider; import store.itpick.backend.model.User; import store.itpick.backend.repository.UserRepository; @@ -15,13 +20,46 @@ import java.util.List; import java.util.Optional; +import static store.itpick.backend.common.response.status.BaseExceptionResponseStatus.EMAIL_NOT_FOUND; +import static store.itpick.backend.common.response.status.BaseExceptionResponseStatus.PASSWORD_NO_MATCH; + @Service @RequiredArgsConstructor public class UserService { private final UserRepository userRepository; - private final BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); + private final PasswordEncoder passwordEncoder; + private final JwtProvider jwtTokenProvider; + + public LoginResponse login(LoginRequest authRequest) { + + String email = authRequest.getEmail(); + + // TODO: 1. 이메일 유효성 확인 + long userId; + try { + userId = userRepository.getUserByEmail(email).get().getUserId(); + } catch (IncorrectResultSizeDataAccessException e) { + throw new UserException(EMAIL_NOT_FOUND); + } + + // TODO: 2. 비밀번호 일치 확인 + validatePassword(authRequest.getPassword(), userId); + + // TODO: 3. JWT 갱신 + String updatedJwt = jwtTokenProvider.createToken(email, userId); + + return new LoginResponse(userId, updatedJwt); + } + + private void validatePassword(String password, long userId) { + String encodedPassword = userRepository.getUserByUserId(userId).get().getPassword(); + if (!passwordEncoder.matches(password, encodedPassword)) { + throw new UserException(PASSWORD_NO_MATCH); + } + } + @Transactional public PostUserResponse signUp(PostUserRequest postUserRequest) { @@ -36,14 +74,14 @@ public PostUserResponse signUp(PostUserRequest postUserRequest) { postUserRequest.setPassword(encodedPassword); // Create user - User user = User.builder().email(postUserRequest.getEmail()).password(encodedPassword).nickname(postUserRequest.getNickname()).birth_date(postUserRequest.getBirth_date()).status("active").build(); + User user = User.builder().email(postUserRequest.getEmail()).password(encodedPassword).nickname(postUserRequest.getNickname()).birthDate(postUserRequest.getBirth_date()).status("active").build(); user = userRepository.save(user); // 회원가입에서 jwt 생성 시 여기에 로직 포함시키기 String jwt = ""; - return new PostUserResponse(user.getId(), jwt); + return new PostUserResponse(user.getUserId(), jwt); } private void validateEmail(String email) {