Skip to content
This repository was archived by the owner on Aug 13, 2022. It is now read-only.

Commit 4f2e0fe

Browse files
committed
SHA-256 암호화방식을 사용해 회원가입기능 구현, 암호 decrypt를통해 로그인 구현, session을 삭제함으로써 로그아웃 구현
1 parent ed3bf6f commit 4f2e0fe

File tree

15 files changed

+401
-64
lines changed

15 files changed

+401
-64
lines changed

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,5 @@ build/
3131
.vscode/
3232

3333

34-
/src/main/resources/application.properties
3534
/.idea/
3635
/et HEAD CONTRIBUTING.md

git

Whitespace-only changes.

src/main/java/com/market/Server/advice/ExceptionAdvice.java

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,39 +13,44 @@
1313

1414
import javax.servlet.http.HttpServletRequest;
1515

16-
@RequiredArgsConstructor
1716
//이 어노테이션은 초기화 되지않은 final 필드나,
1817
//@NonNull 이 붙은 필드에 대해 생성자를 생성해 줍니다.
1918
//주로 의존성 주입(Dependency Injection) 편의성을 위해서 사용되곤 합니다.
19+
@RequiredArgsConstructor
20+
// ControllerAdvice의 annotation은 @ControllerAdvice @RestControllerAdvice 두가지가 있습니다. 예외 발생 시 json형태로 결과를 반환하려면
21+
// @RestControllerAdvice를 클래스에 선언하면 됩니다. annotation에 추가로 패키지를 적용하면 위에서 설명한 것처럼 특정 패키지 하위의 Controller에만 로직이 적용되게도 할 수 있습니다.
22+
// ex) @RestControllerAdvice(basePackages = “com.rest.api”)
23+
// 아무것도 적용하지 않으면 프로젝트의 모든 Controller에 로직이 적용됩니다.
2024
@RestControllerAdvice
21-
//ControllerAdvice의 annotation은 @ControllerAdvice @RestControllerAdvice 두가지가 있습니다. 예외 발생 시 json형태로 결과를 반환하려면
22-
//@RestControllerAdvice를 클래스에 선언하면 됩니다. annotation에 추가로 패키지를 적용하면 위에서 설명한 것처럼 특정 패키지 하위의 Controller에만 로직이 적용되게도 할 수 있습니다.
23-
//ex) @RestControllerAdvice(basePackages = “com.rest.api”)
24-
//실습에서는 아무것도 적용하지 않아 프로젝트의 모든 Controller에 로직이 적용됩니다.
2525
public class ExceptionAdvice {
2626
private final ResponseService responseService;
2727
private final MessageSource messageSource;
28-
@ExceptionHandler(Exception.class)
28+
2929
//Exception이 발생하면 해당 Handler로 처리하겠다고 명시하는 annotation입니다. 괄호안에는 어떤 Exception이 발생할때 handler를 적용할 것인지
3030
//Exception Class를 인자로 넣습니다. 예제에서는 Exception.class를 지정하였는데 Exception.class는 최상위 예외처리 객체이므로 다른
3131
//ExceptionHandler에서 걸러지지 않은 예외가 있으면 최종으로 이 handler를 거쳐 처리됩니다. 그래서 메서드 명도 defaultException이라 명명하였습니다.
32-
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
32+
@ExceptionHandler(Exception.class)
33+
3334
//해당 Exception이 발생하면 Response에 출력되는 HttpStatus Code가 500으로 내려가도록 설정합니다.
3435
//참고로 성공 시엔 HttpStatus code가 200으로 내려갑니다. 실습에서 HttpStatus Code의 역할은 성공이냐(200)
3536
//아니냐 정도의 의미만 있고 실제 사용하는 성공 실패 여부는 json으로 출력되는 정보를 이용합니다.
37+
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
3638
protected CommonResult defaultException(HttpServletRequest request, Exception e) {
3739
return responseService.getFailResult(Integer.valueOf(getMessage("unKnown.code")), getMessage("unKnown.msg"));
3840
}
41+
3942
@ExceptionHandler(CUserNotFoundException.class)
4043
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
4144
protected CommonResult userNotFoundException(HttpServletRequest request, CUserNotFoundException e) {
4245
// 예외 처리의 메시지를 MessageSource에서 가져오도록 수정
4346
return responseService.getFailResult(Integer.valueOf(getMessage("userNotFound.code")), getMessage("userNotFound.msg"));
4447
}
48+
4549
// code정보에 해당하는 메시지를 조회합니다.
4650
private String getMessage(String code) {
4751
return getMessage(code, null);
4852
}
53+
4954
// code정보, 추가 argument로 현재 locale에 맞는 메시지를 조회합니다.
5055
private String getMessage(String code, Object[] args) {
5156
return messageSource.getMessage(code, args, LocaleContextHolder.getLocale());
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package com.market.Server.advice.exception;
2+
3+
public class DuplicateIdException extends RuntimeException {
4+
5+
public DuplicateIdException(String msg) {
6+
super(msg);
7+
}
8+
9+
}
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
package com.market.Server.controller;
2+
3+
import com.market.Server.dto.UserDTO;
4+
import com.market.Server.service.ResponseService;
5+
import com.market.Server.service.UserServiceImpl;
6+
import com.market.Server.utils.SessionUtil;
7+
import com.sun.istack.internal.NotNull;
8+
import io.swagger.annotations.Api;
9+
import lombok.*;
10+
import lombok.extern.log4j.Log4j2;
11+
import org.springframework.beans.factory.annotation.Autowired;
12+
import org.springframework.http.HttpStatus;
13+
import org.springframework.http.ResponseEntity;
14+
import org.springframework.web.bind.annotation.*;
15+
16+
import javax.servlet.http.HttpSession;
17+
18+
19+
@Api(tags = {"2. users"})
20+
@RestController
21+
@RequestMapping("/user")
22+
@Log4j2
23+
public class UserController {
24+
25+
private final UserServiceImpl userService ;
26+
27+
@Autowired
28+
public UserController(UserServiceImpl userService, ResponseService responseService) {
29+
this.userService=userService;
30+
}
31+
32+
/**
33+
* 로그인한 사용자가 마이페이지를 눌렀을 때 보여줄 사용자 정보를 반환한다.
34+
*
35+
* @param session 현재 사용자의 세션
36+
* @return UserDTO
37+
*/
38+
@GetMapping("myInfo")
39+
public UserInfoResponse memberInfo(HttpSession session) {
40+
String id = SessionUtil.getLoginMemberId(session);
41+
UserDTO memberInfo = userService.getUserInfo(id);
42+
return new UserInfoResponse(memberInfo);
43+
}
44+
45+
46+
/**
47+
* 유저가 입력한 정보로 회원가입을 진행한다. 보낸 값들 중 NULL값이 있으면 "NULL_ARGUMENT" 를 리턴한다. 회원가입 요청을 보내기 전 먼저 ID 중복체크를
48+
* 진행한다. ID 중복시 403 상태코드를 반환한다. 회원가입 성공시 201 상태코드를 반환한다.
49+
*
50+
* @param userDTO 회원가입을 요청한 정보
51+
* @return
52+
*
53+
*/
54+
@PostMapping("sign up")
55+
@ResponseStatus(HttpStatus.CREATED)
56+
public void signUp(@RequestBody @NotNull UserDTO userDTO) {
57+
if(UserDTO.hasNullDataBeforeSignup(userDTO)){
58+
throw new NullPointerException("회원가입시 필수 데이터를 모두 입력해야 합니다.");
59+
}
60+
userService.register(userDTO);
61+
}
62+
/**
63+
* 회원 로그인을 진행한다. Login 요청시 id, password가 NULL일 경우 NullPointerException을 throw한다.
64+
*/
65+
@PostMapping("login")
66+
public ResponseEntity<LoginResponse> login(@RequestBody @NotNull UserLoginRequest loginRequest,
67+
HttpSession session) {
68+
ResponseEntity<LoginResponse> responseEntity = null;
69+
String id = loginRequest.getId();
70+
String password = loginRequest.getPassword();
71+
LoginResponse loginResponse;
72+
UserDTO userInfo = userService.login(id, password);
73+
74+
if (userInfo == null) {
75+
// ID, Password에 맞는 정보가 없을 때
76+
loginResponse = LoginResponse.FAIL;
77+
responseEntity = new ResponseEntity<UserController.LoginResponse>(loginResponse,
78+
HttpStatus.UNAUTHORIZED);
79+
} else if (UserDTO.Status.DEFAULT.equals(userInfo.getStatus())) {
80+
// 성공시 세션에 ID를 저장
81+
loginResponse = LoginResponse.success(userInfo);
82+
SessionUtil.setLoginMemberId(session, id);
83+
responseEntity = new ResponseEntity<LoginResponse>(loginResponse, HttpStatus.OK);
84+
} else {
85+
// 예상하지 못한 오류일 경우
86+
log.error("login ERROR" + responseEntity);
87+
throw new RuntimeException("login ERROR!");
88+
}
89+
90+
return responseEntity;
91+
}
92+
93+
/**
94+
* 회원 로그아웃 메서드.
95+
*
96+
* @author jun
97+
* @param session 현제 접속한 세션
98+
* @return 로그인 하지 않았을 시 401코드를 반환하고 result:NO_LOGIN 반환 로그아웃 성공시 200 코드를 반환
99+
*/
100+
@GetMapping("logout")
101+
public void logout(HttpSession session) {
102+
SessionUtil.logoutMember(session);
103+
}
104+
105+
@Getter
106+
@AllArgsConstructor
107+
private static class UserInfoResponse {
108+
private UserDTO userDTO;
109+
}
110+
111+
// -------------- response 객체 --------------
112+
113+
@Getter
114+
@AllArgsConstructor
115+
// 필드값을 모두 포함한 생성자를 자동 생성해준다.
116+
@RequiredArgsConstructor
117+
// 생성자를 자동 생성하지만, 필드명 위에 @NonNull로 표기된 경우만 생성자의 매개변수로 받는다.
118+
private static class LoginResponse {
119+
enum LoginStatus {
120+
SUCCESS, FAIL, DELETED
121+
}
122+
123+
@NonNull
124+
private LoginStatus result;
125+
private UserDTO userDTO;
126+
127+
// success의 경우 userInfo의 값을 set해줘야 하기 때문에 new 하도록 해준다.
128+
private static final LoginResponse FAIL = new LoginResponse(LoginStatus.FAIL);
129+
private static LoginResponse success(UserDTO userDTO) {
130+
return new LoginResponse(LoginStatus.SUCCESS, userDTO);
131+
}
132+
133+
134+
}
135+
136+
// -------------- request 객체 --------------
137+
138+
@Setter
139+
@Getter
140+
private static class UserLoginRequest {
141+
@NonNull
142+
private String id;
143+
@NonNull
144+
private String password;
145+
}
146+
}

src/main/java/com/market/Server/controller/UserRegisterController.java

Lines changed: 0 additions & 52 deletions
This file was deleted.

src/main/java/com/market/Server/dto/UserDTO.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,22 @@ public class UserDTO {
1111
public enum Status {
1212
DEFAULT, DELETED
1313
}
14+
1415
private String id;
1516
private String pw;
1617
private String name;
1718
private String phone;
1819
private String address;
20+
private Status status;
1921

2022

21-
public UserDTO(String id, String pw, String name, String phone, String address) {
23+
public UserDTO(String id, String pw, String name, String phone, String address, Status status) {
2224
this.id = id;
2325
this.pw =pw;
2426
this.name = name;
2527
this.phone = phone;
2628
this.address = address;
29+
this.status = status;
2730
}
2831

2932
/**

src/main/java/com/market/Server/mapper/UserProfileMapper.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,7 @@ public interface UserProfileMapper {
2020

2121
public int register(UserDTO userDTO);
2222

23+
public UserDTO findByIdAndPassword(@Param("id") String id, @Param("pw") String pw);
2324

25+
int idCheck(String id);
2426
}

src/main/java/com/market/Server/service/ResponseService.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77

88
import java.util.List;
99

10+
11+
// 해당 Class가 서비스(서버에서 클라이언트에게 응답할때 response 패킷을 정의) 레이어 클래스라는 것을 spring framework에 정의한다.
12+
// response를 class로 분리한 이유는 해당 클래스를 사용하는 곳에서 ExceptionHandler의 형태를 직접 정의한다.
1013
@Service
1114
public class ResponseService {
1215
// enum으로 api 요청 결과에 대한 code, message를 정의합니다.

src/main/java/com/market/Server/service/UserService.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@ public interface UserService {
66

77
// 회원 가입 처리
88
void register(UserDTO userProfile);
9+
910
}
Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
package com.market.Server.service;
22

3+
import com.market.Server.advice.exception.DuplicateIdException;
34
import com.market.Server.mapper.UserProfileMapper;
45
import com.market.Server.dto.UserDTO;
6+
import com.market.Server.utils.SHA256Util;
7+
import lombok.extern.log4j.Log4j2;
58
import org.springframework.beans.factory.annotation.Autowired;
69
import org.springframework.stereotype.Service;
710

811
@Service
12+
@Log4j2
13+
// https://logging.apache.org/log4j/2.x/
914
public class UserServiceImpl implements UserService {
1015

1116
@Autowired
@@ -15,10 +20,61 @@ public UserServiceImpl(UserProfileMapper userProfileMapper){
1520
this.userProfileMapper=userProfileMapper;
1621
}
1722

18-
// 회원 가입 처리
23+
24+
public UserDTO getUserInfo(String userId) {
25+
return userProfileMapper.getUserProfile(userId);
26+
}
27+
28+
/**
29+
* 회원 가입 메서드.
30+
*
31+
* @param UserDTO 저장할 회원의 정보
32+
* @return
33+
*
34+
* - 고객 회원가입 메서드 비밀번호를 암호화하여 세팅한다. MyBatis에서 insert return값은 성공시 1이 리턴된다. return값은 검사하여 null값이면
35+
* true, null이 아닐시 insert에 실패한 것이니 false를 반환한다
36+
*/
1937
@Override
2038
public void register(UserDTO userDTO) {
21-
userProfileMapper.register(userDTO);
39+
// id 중복체크
40+
boolean duplIdResult = isDuplicatedId(userDTO.getId());
41+
if (duplIdResult) {
42+
throw new DuplicateIdException("중복된 아이디입니다.");
43+
}
44+
45+
userDTO.setPw(SHA256Util.encryptSHA256(userDTO.getPw()));
46+
int insertCount = userProfileMapper.register(userDTO);
47+
48+
if (insertCount != 1) {
49+
log.error("insertMember ERROR! {}", userDTO);
50+
throw new RuntimeException(
51+
"insertUser ERROR! 회원가입 메서드를 확인해주세요\n" + "Params : " + userDTO);
52+
}
2253
}
2354

55+
/**
56+
* 고객 로그인 메서드.
57+
*
58+
* @param id 고객 아이디
59+
* @param password 고객 비밀번호
60+
* @return
61+
*/
62+
public UserDTO login(String id, String password) {
63+
String cryptoPassword = SHA256Util.encryptSHA256(password);
64+
UserDTO memberInfo = userProfileMapper.findByIdAndPassword(id, cryptoPassword);
65+
return memberInfo;
66+
}
67+
68+
/**
69+
* 회원가입시 아이디 중복 체크를 진행한다.
70+
*
71+
* @param id 중복체크를 진행할 아이디
72+
* @return true : 중복된 아이디 false : 중복되지 않은 아이디(생성 가능한 아이디)
73+
*/
74+
public boolean isDuplicatedId(String id) {
75+
return userProfileMapper.idCheck(id) == 1;
76+
}
77+
78+
79+
2480
}

0 commit comments

Comments
 (0)