From ec9d54a0bfa7accf9d856bad126854ec91132119 Mon Sep 17 00:00:00 2001 From: knh0113 <80758615+knh0113@users.noreply.github.com> Date: Tue, 26 Sep 2023 17:26:14 +0900 Subject: [PATCH] =?UTF-8?q?=EC=9E=90=EB=8F=99=20=EB=A1=9C=EA=B7=B8?= =?UTF-8?q?=EC=9D=B8=20(#58)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 자동 로그인 * 로그인, 회원가입 초안 * 자동 로그인기능, 로그인 회원가입 화면 초안 * fix : 검증문제 해결 * 회원가입시 패스워드 수정 * 자동로그인 화면 수정 * 자동로그인 수정 * 자동 로그인 수정2 * 자동 로그인 수정3 * feat : Exception 추가 * checkout을 위한 Commit * 사용자 수정 * 로그인 화면 수정 * 사용자 수정2 * 로그인 화면 수정 * 사용자 수정2 * feat : 입찰기능 추가 (#71) * refactor, feat : 컬럼 추가, 타입변경 및 rename 에 따른 기능 수정 * feat : Scheduling완료, Mail Template 페이지제작 * tempSave * feat : 입찰 기능 구현 * feat : checkout을 위한 Commit * feat : Emial Template 제작중 * feat : 이메일 구현 - 입찰자가 없는 경우 유찰 안내메일 - 관리자가 승인하지 않은 경우 유찰 안내메일 - 경매 시작 안내 메일 - 링크 발송을 위한 Properties 추가 * Issue 수정 * feat : detail페이지 이쁘게 꾸미기 * faet : Front로직 추가~ * Feat : 입찰기능 추가 * 사용자 수정3 * merge --------- Co-authored-by: donsonioc2010 Co-authored-by: Jong1 <44349716+donsonioc2010@users.noreply.github.com> --- .../api/user/controller/AuthController.java | 176 +++++++++++------- .../user/exception/EmailErrorException.java | 11 ++ .../user/exception/LoginErrorException.java | 13 ++ .../user/exception/StatusErrorException.java | 11 ++ .../server/api/user/service/UserService.java | 42 ++--- Api/src/main/resources/static/css/login.css | 33 ++++ Api/src/main/resources/static/css/signup.css | 41 ++++ Api/src/main/resources/static/js/signup.js | 12 ++ .../main/resources/templates/auth/login.html | 93 ++++++--- .../resources/templates/auth/signup-form.html | 68 ++++--- .../common/exception/GlobalException.java | 9 +- .../domain/domains/user/entity/User.java | 1 + .../user/repository/UserRepository.java | 1 + 13 files changed, 372 insertions(+), 139 deletions(-) create mode 100644 Api/src/main/java/picasso/server/api/user/exception/EmailErrorException.java create mode 100644 Api/src/main/java/picasso/server/api/user/exception/LoginErrorException.java create mode 100644 Api/src/main/java/picasso/server/api/user/exception/StatusErrorException.java create mode 100644 Api/src/main/resources/static/css/login.css create mode 100644 Api/src/main/resources/static/css/signup.css create mode 100644 Api/src/main/resources/static/js/signup.js diff --git a/Api/src/main/java/picasso/server/api/user/controller/AuthController.java b/Api/src/main/java/picasso/server/api/user/controller/AuthController.java index be72e3cd..9dc01e0f 100644 --- a/Api/src/main/java/picasso/server/api/user/controller/AuthController.java +++ b/Api/src/main/java/picasso/server/api/user/controller/AuthController.java @@ -1,6 +1,8 @@ package picasso.server.api.user.controller; -import com.fasterxml.jackson.core.JsonProcessingException; +import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpSession; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -27,72 +29,120 @@ @RequiredArgsConstructor public class AuthController { - private final UserService userService; + private final UserService userService; - /** - * 로그인 폼으로 이동 - * - * @return - */ - @GetMapping("/login") - public String showLoginForm(HttpSession session) { - // TODO : 페이지 들어올때 자동로그인 설정 된 경우 Cookie 받아서 처리하는 로직 추가하기 - return "auth/login"; - } + /** + * 로그인 폼으로 이동 + * + * @return + */ +// @GetMapping("/login") +// public String showLoginForm(HttpSession session) { +// // TODO : 페이지 들어올때 자동로그인 설정 된 경우 Cookie 받아서 처리하는 로직 추가하기 +// return "auth/login"; +// } + @GetMapping("/login") + public String showLoginForm(HttpSession session, HttpServletRequest request) { + //쿠키를 확인하여 자동 로그인 처리 + Cookie[] cookies = request.getCookies(); + String userId = null; + String email = null; - /** - * 로그인 기능 구현 - * - * @param requestDto - * @param session - * @return - * @throws JsonProcessingException - */ - @PostMapping("/login") - public String handleLogin(LoginRequestDto requestDto, HttpSession session) throws JsonProcessingException { - session.removeAttribute("loginUser"); - Optional findResult = userService.login(requestDto); - findResult.ifPresent(user -> setSessionLoginUser(session, user)); - if (findResult.isEmpty()) - return "redirect:/auth/login"; - return "redirect:/"; + if (cookies != null) { + for (Cookie cookie : cookies) { + if (cookie.getName().equals("userId")) { + userId = cookie.getValue(); + } else if (cookie.getName().equals("email")) { + email = cookie.getValue(); + } + } + } + if (userId != null && email != null) { + Optional findResult = userService.findUserByIdAndEmail(Long.parseLong(userId), email); + findResult.ifPresent(user -> { + setSessionLoginUser(session, user); + }); + if (findResult.isPresent()) { + return "redirect:/"; // 성공적으로 사용자를 찾으면 메인 페이지로 리다이렉트 + } } + return "auth/login"; + } - /** - * 회원가입 폼으로 이동 - * - * @return - */ - @GetMapping("/signup") - public String showSignUpForm() { - return "auth/signup-form"; - } + /* + * 로그인 기능 구현 + * + * @param requestDto + * @param session + * @return + * @throws JsonProcessingException + */ - /** - * 회원가입 처리 로직 - * - * @param requestDto - * @return - */ - @PostMapping("/signup") - public String signUp(SignUpRequestDto requestDto, HttpSession session) { - setSessionLoginUser(session, userService.signUp(requestDto)); - return "redirect:/"; - } - private void setSessionLoginUser(HttpSession session, User user) { - session.setAttribute("loginUser", user); - } - - @ResponseBody - @PostMapping("/session-info") - public Map paymentSessionInfoRtn(HttpSession session) { - User temp = (User)session.getAttribute("loginUser"); - Long userId = userService.findUserById(temp.getId()).orElseThrow( - () -> UserNotFoundException.EXCEPTION - ).getId(); - return new HashMap(){{ - put("userId", userId); - }}; - } + @PostMapping("/login") + public String handleLogin(LoginRequestDto requestDto, HttpSession session, HttpServletResponse response) { + session.removeAttribute("loginUser"); + Optional findResult = userService.login(requestDto); + findResult.ifPresent(user -> { + setSessionLoginUser(session, user); + // 자동 로그인 쿠키 생성 + // TODO : Email 쿠키 ㅇㄷ?, ACTIVE가 아니면 로그인 안되게 처리하는 로직 ㅇㄷ? + if (requestDto.isRememberMe()) { + Cookie cookie1 = new Cookie("userId", user.getId().toString()); + Cookie cookie2 = new Cookie("email", user.getEmail()); + cookie1.setMaxAge(60 * 60 * 24 * 365); + cookie2.setMaxAge(60 * 60 * 24 * 365); + response.addCookie(cookie1); + response.addCookie(cookie2); + } + }); + if (findResult.isEmpty()) + return "redirect:/auth/login"; + return "redirect:/"; + } + + + @GetMapping("/logout") + public String showLogoutForm(HttpSession session) { + session.removeAttribute("loginUser"); + // 로그아웃 폼 페이지를 보여줍니다. + return "redirect:/"; + } + + /** + * 회원가입 폼으로 이동 + * + * @return + */ + @GetMapping("/signup") + public String showSignUpForm() { + return "auth/signup-form"; + } + + /** + * 회원가입 처리 로직 + * + * @param requestDto + * @return + */ + @PostMapping("/signup") + public String signUp(SignUpRequestDto requestDto, HttpSession session) { + setSessionLoginUser(session, userService.signUp(requestDto)); + return "redirect:/"; + } + private void setSessionLoginUser(HttpSession session, User user) { + session.setAttribute("loginUser", user); + } + + @ResponseBody + @PostMapping("/session-info") + public Map paymentSessionInfoRtn(HttpSession session) { + User temp = (User)session.getAttribute("loginUser"); + Long userId = userService.findUserById(temp.getId()).orElseThrow( + () -> UserNotFoundException.EXCEPTION + ).getId(); + return new HashMap(){{ + put("userId", userId); + }}; + } } diff --git a/Api/src/main/java/picasso/server/api/user/exception/EmailErrorException.java b/Api/src/main/java/picasso/server/api/user/exception/EmailErrorException.java new file mode 100644 index 00000000..454ea60f --- /dev/null +++ b/Api/src/main/java/picasso/server/api/user/exception/EmailErrorException.java @@ -0,0 +1,11 @@ +package picasso.server.api.user.exception; + +import picasso.server.common.exception.BaseException; + +import static picasso.server.common.exception.GlobalException.EMAIL_ERROR; + +public class EmailErrorException extends BaseException { + public static final BaseException EXCEPTION = new EmailErrorException(); + + public EmailErrorException() { super(EMAIL_ERROR);} +} diff --git a/Api/src/main/java/picasso/server/api/user/exception/LoginErrorException.java b/Api/src/main/java/picasso/server/api/user/exception/LoginErrorException.java new file mode 100644 index 00000000..76bcd11c --- /dev/null +++ b/Api/src/main/java/picasso/server/api/user/exception/LoginErrorException.java @@ -0,0 +1,13 @@ +package picasso.server.api.user.exception; + +import picasso.server.common.exception.BaseException; + +import static picasso.server.common.exception.GlobalException.LOGIN_ERROR; + +public class LoginErrorException extends BaseException { + public static final BaseException EXCEPTION = new LoginErrorException(); + + public LoginErrorException() { + super(LOGIN_ERROR); + } +} \ No newline at end of file diff --git a/Api/src/main/java/picasso/server/api/user/exception/StatusErrorException.java b/Api/src/main/java/picasso/server/api/user/exception/StatusErrorException.java new file mode 100644 index 00000000..d48b64c0 --- /dev/null +++ b/Api/src/main/java/picasso/server/api/user/exception/StatusErrorException.java @@ -0,0 +1,11 @@ +package picasso.server.api.user.exception; + +import picasso.server.common.exception.BaseException; + +import static picasso.server.common.exception.GlobalException.STATUS_ERROR; + +public class StatusErrorException extends BaseException { + public static final BaseException EXCEPTION = new StatusErrorException(); + + public StatusErrorException() { super(STATUS_ERROR); } +} diff --git a/Api/src/main/java/picasso/server/api/user/service/UserService.java b/Api/src/main/java/picasso/server/api/user/service/UserService.java index 83e15ad2..b597fb99 100644 --- a/Api/src/main/java/picasso/server/api/user/service/UserService.java +++ b/Api/src/main/java/picasso/server/api/user/service/UserService.java @@ -1,15 +1,11 @@ package picasso.server.api.user.service; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import jakarta.servlet.http.Cookie; -import jakarta.servlet.http.HttpServletRequest; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; +import picasso.server.api.user.exception.EmailErrorException; import picasso.server.api.user.vo.request.LoginRequestDto; import picasso.server.api.user.vo.request.SignUpRequestDto; -import picasso.server.domain.domains.user.dto.UserDTO; import picasso.server.domain.domains.user.entity.User; import picasso.server.domain.domains.user.repository.UserRepository; @@ -22,9 +18,15 @@ public class UserService { private final UserRepository userRepository; - private final ObjectMapper objectMapper; public User signUp(SignUpRequestDto userDto) { + + Optional existingUser = userRepository.findByEmail(userDto.getEmail()); + if (existingUser.isPresent()) { + // TODO : Custom Exception ㅇㄷ? + throw EmailErrorException.EXCEPTION; // 중복 이메일 체크 + } + return userRepository.save(User.builder() .email(userDto.getEmail()) .password(userDto.getPassword()) @@ -38,24 +40,6 @@ public Optional login(LoginRequestDto userDto) { return findUser; } - public boolean isUserValid(UserDTO userDto, HttpServletRequest request) throws JsonProcessingException { - // 1. 쿠키에서 "user" 데이터를 가져옵니다. - Cookie[] cookies = request.getCookies(); - if (cookies != null) { - for (Cookie cookie : cookies) { - if ("user".equals(cookie.getName())) { - // 2. 가져온 데이터를 User 객체로 변환합니다. - User userFromCookie = objectMapper.readValue(cookie.getValue(), User.class); - - // 3. 변환된 User 객체와 입력받은 UserDTO 데이터를 비교합니다. - if (userDto.getEmail().equals(userFromCookie.getEmail()) && userDto.getPassword().equals(userFromCookie.getPassword())) { - return true; // 쿠키의 데이터와 입력된 데이터가 일치합니다. - } - } - } - } - return false; // 일치하는 쿠키 데이터가 없거나, 데이터가 입력과 일치하지 않습니다. - } public Optional findUserByEmailAndPassword(String email, String password) { @@ -66,6 +50,7 @@ public Optional findUserByNickname(String nickname) { return userRepository.findByNickName(nickname); } + public void deleteUserById(Long id) { userRepository.deleteById(id); } @@ -73,6 +58,15 @@ public Optional findUserById(Long id) { return userRepository.findById(id); } + //?? + public Optional findUserByIdAndEmail(Long userId, String email) { + return userRepository.findByIdAndEmail(userId, email); + } + + public Optional findUserByEmail(String email) { + return userRepository.findByEmail(email); + } + public Optional findById(Long userId) { return userRepository.findById(userId); } diff --git a/Api/src/main/resources/static/css/login.css b/Api/src/main/resources/static/css/login.css new file mode 100644 index 00000000..7c35d9b7 --- /dev/null +++ b/Api/src/main/resources/static/css/login.css @@ -0,0 +1,33 @@ + #login-box { + margin: 80px; + background-color: white; + display: flex; + flex-direction: column; + border-radius: 70px; + justify-content: center; + align-items: center; + height: 50vh; + margin-left: 37%; + border: 10px solid #18ACDB; + width: 380px; + } + + #login-title { + text-align: center; + font-family: Sigmar One; + font-style: normal; + color: #18ACDB; + } + + #email, #password { + text-align: center; + } + + #rememberMe-container { + text-align: center; + } + + .btn-primary.before-login-btn { + text-align: center; + margin-left: 28%; + } \ No newline at end of file diff --git a/Api/src/main/resources/static/css/signup.css b/Api/src/main/resources/static/css/signup.css new file mode 100644 index 00000000..bce8d9b2 --- /dev/null +++ b/Api/src/main/resources/static/css/signup.css @@ -0,0 +1,41 @@ +signup-container { + margin: 80px; + background-color: white; + display: flex; + flex-direction: column; + border-radius: 70px; + justify-content: center; + align-items: center; + height: 50vh; + margin-left: 37%; + border: 10px solid #18ACDB; + width: 380px; +} + +signup-form { + /* form 관련 스타일 추가 */ +} + +signup-title { + text-align: center; + font-family: Sigmar One; + font-style: normal; + color: #18ACDB; +} + +signup-table { + /* table 관련 스타일 추가 */ +} + +#nickname, +#email, +#password, +#repeatPassword { + background-color: #E8F0FE; + text-align: center; +} + +register-button { + text-align: center; + margin-left: 20%; +} diff --git a/Api/src/main/resources/static/js/signup.js b/Api/src/main/resources/static/js/signup.js new file mode 100644 index 00000000..08a52882 --- /dev/null +++ b/Api/src/main/resources/static/js/signup.js @@ -0,0 +1,12 @@ +// function validatePassword() { +// window.alert('password functions'); +// var passwd = document.getElementById("password").value; +// var repeatPasswd = document.getElementById("repeatPassword").value; +// if (password !== confirmPassword) { +// alert("패스워드가 일치하지 않습니다"); +// return false; +// } +// return true; +// } +// +// validatePassword(); \ No newline at end of file diff --git a/Api/src/main/resources/templates/auth/login.html b/Api/src/main/resources/templates/auth/login.html index 6abb200c..ea32e320 100644 --- a/Api/src/main/resources/templates/auth/login.html +++ b/Api/src/main/resources/templates/auth/login.html @@ -4,32 +4,83 @@ xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" - layout:decorate="~{layout/layout}" -> + layout:decorate="~{layout/layout}"> + + + +
-

로그인

-
-
- - -
-
- - -
-
- - -
- -
+ + +
+ +
+
- + function loginCheck(){ + var email = document.getElementById('email').value; + var password = document.getElementById('password').value; + + if (!email || !password) { + alert('아이디와 비밀번호를 모두 입력해주세요.'); + return false; + } + return true; + + diff --git a/Api/src/main/resources/templates/auth/signup-form.html b/Api/src/main/resources/templates/auth/signup-form.html index f4766254..ab800fa7 100644 --- a/Api/src/main/resources/templates/auth/signup-form.html +++ b/Api/src/main/resources/templates/auth/signup-form.html @@ -4,32 +4,48 @@ xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" - layout:decorate="~{layout/layout}" -> + layout:decorate="~{layout/layout}"> +
+
+
+

JOIN


+ + + + + + + + + + + + + +

+ + + +
+
+
+ + + - - + if (password !== repeatPassword) { + alert("비밀번호를 확인해 주세요."); + return false; // 회원가입 중단 + } + + return true; // 비밀번호가 일치하면 회원가입 진행 +} + + + + diff --git a/Common/src/main/java/picasso/server/common/exception/GlobalException.java b/Common/src/main/java/picasso/server/common/exception/GlobalException.java index fa5a6d02..df16316d 100644 --- a/Common/src/main/java/picasso/server/common/exception/GlobalException.java +++ b/Common/src/main/java/picasso/server/common/exception/GlobalException.java @@ -2,13 +2,9 @@ import lombok.AllArgsConstructor; import lombok.Getter; -import org.springframework.http.HttpStatus; import picasso.server.common.dto.ErrorDetail; -import static org.springframework.http.HttpStatus.BAD_REQUEST; -import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR; -import static org.springframework.http.HttpStatus.NOT_FOUND; -import static org.springframework.http.HttpStatus.UNAUTHORIZED; +import static org.springframework.http.HttpStatus.*; @Getter @AllArgsConstructor @@ -29,6 +25,9 @@ public enum GlobalException implements BaseErrorCode { PICTURE_STATUS_AFTER_APPROVE(INTERNAL_SERVER_ERROR.value(), "이미 관리자가 승인한 게시물 입니다."), NOT_LOGIN_EXCEPTION(UNAUTHORIZED.value(), "로그인이 필요합니다."), NEED_LOGIN_ERROR(UNAUTHORIZED.value(), "로그인이 필요한 기능입니다."), + LOGIN_ERROR(NOT_FOUND.value(), "자동로그인 실패"), + STATUS_ERROR(NOT_FOUND.value(), "비활성화되어 있습니다"), + EMAIL_ERROR(NOT_FOUND.value(), "이메일이 없습니다"), USER_NOT_FOUND_ERROR(NOT_FOUND.value(), "유저를 찾을 수 없습니다.") ; diff --git a/Domain/src/main/java/picasso/server/domain/domains/user/entity/User.java b/Domain/src/main/java/picasso/server/domain/domains/user/entity/User.java index 381fdfaf..d8140594 100644 --- a/Domain/src/main/java/picasso/server/domain/domains/user/entity/User.java +++ b/Domain/src/main/java/picasso/server/domain/domains/user/entity/User.java @@ -91,6 +91,7 @@ public class User { private LocalDateTime updatedAt = LocalDateTime.now(); @NotNull + @Column @Builder.Default private LocalDateTime loginAt = LocalDateTime.now(); diff --git a/Domain/src/main/java/picasso/server/domain/domains/user/repository/UserRepository.java b/Domain/src/main/java/picasso/server/domain/domains/user/repository/UserRepository.java index 6fd4522a..ffd7a7eb 100644 --- a/Domain/src/main/java/picasso/server/domain/domains/user/repository/UserRepository.java +++ b/Domain/src/main/java/picasso/server/domain/domains/user/repository/UserRepository.java @@ -17,5 +17,6 @@ public interface UserRepository extends JpaRepository { Optional findByEmailAndPassword(String email, String password); + Optional findByIdAndEmail(Long userId, String email); }