[ 작업한 내용 ]
< 공용: 회원가입 >
# JoinReqDTO
- 회원가입 요청 DTO 정의
- 사용자 아이디, 비밀번호, 이메일 (username, password, email)
@Getter
public class JoinReqDTO {
private String username;
private String password;
private String email;
}
# JoinResDTO
- 회원가입 응답 DTO 정의
- 사용자 고유번호, 사용자 아이디 (id, username)
- User 엔티티를 파라미터로 받는 생성자 함수 정의
@Getter
public class JoinResDTO {
private Long id;
private String username;
public JoinResDTO(User user) {
this.id = user.getId();
this.username = user.getUsername();
}
}
# AuthController
- POST /api/v1/auth/signup 으로 요청합니다.
- 파라미터로 JoinReqDTO를 받으며, JoinReqDTO의 구성은 username, password, email입니다.
- Service계층으로 request(username, password, email)을 전달합니다.
- 반환 받은 결과는 JoinResDTO 형태로 저장합니다.
- 클라이언트 측으로 성공 메시지와 결과를 ApiResponse.success()로 감싸서 응답합니다.
// 공용: 회원가입
@PostMapping("/signup")
public ResponseEntity<?> singUp(@RequestBody JoinReqDTO request) {
// 서비스로직
JoinResDTO resonseDTO = authService.signUp(request);
// 성공메시지
String message = messageProvider.getMessage(UserSuccessCode.USER_CREATED.getMessage());
// 응답
return ResponseEntity
.status(UserSuccessCode.USER_CREATED.getHttpStatus())
.body(ApiResponse.success(
UserSuccessCode.USER_CREATED,
message,
resonseDTO));
}
# AuthService
- userRepository.existsByUsername(request.getUsername())으로 아이디 중복 체크를 합니다. 아이디가 중복이 되면
- userRepository.existsByEmail(request.getEmail())로 이메일 중복 체크를 합니다.
- 요청받은 DTO를 가지고 User 엔티티를 생성하고 userRepository.save(user)을 사용하여 DB에 User 객체를 저장한다.
- Controller 계층으로 user를 기반으로 JoinResDTO 객체를 생성하여 반환한다.
/*
* 공용: 회원가입
*/
@Transactional
public JoinResDTO signUp(JoinReqDTO request) {
// 아이디 중복 체크
if (userRepository.existsByUsername(request.getUsername())) {
throw new BaseException(UserErrorCode.USER_USERNAME_DUPLICATED);
}
// 이메일 중복 체크
if (userRepository.existsByEmail(request.getEmail())) {
throw new BaseException(UserErrorCode.USER_EMAIL_DUPLICATED);
}
// User 엔티티 생성
User user = User.builder()
.username(request.getUsername())
.password(passwordEncoder.encode(request.getPassword()))
.email(request.getEmail())
.role(Role.ROLE_USER)
.joinDate(LocalDateTime.now())
.build();
// user 저장
userRepository.save(user);
// 반환
return new JoinResDTO(user);
}
# UserRepository
- 아이디 중복 체크를 위해 boolean exsistsByUsername(String username); 메서드 생성.
- 이메일 중복 체크를 위해 boolean exsistsByEmail(String email); 메서드 생성
// 아이디 중복 체크
boolean existsByUsername(String username);
// 이메일 중복 체크
boolean existsByEmail(String email);
< 공용: 로그인 >
# LoginReqDTO
- 로그인 요청 DTO 정의
- 사용자 아이디, 비밀번호 (username, password)
@Getter
public class LoginReqDTO {
private String username;
private String password;
}
# LoginResDTO
- 로그인 응답 DTO 정의
- 사용자 아이디, 토큰 (username, token)
- User 엔티티와 String token을 파라미터로 받는 생성자 함수 정의
@Getter
public class LoginResDTO {
private String username;
private String token;
public LoginResDTO(User user, String token) {
this.username = user.getUsername();
this.token = token;
}
}
# AuthController
- POST /api/v1/auth/signin 으로 요청합니다.
- 파라미터로 LoginReqDTO를 받으며, LoginReqDTO의 구성은 username, password 입니다.
- Service계층으로 request(username, password)을 전달합니다.
- 반환 받은 결과는 LoginResDTO 형태로 저장합니다.
- ResponseCookie형태로 responseDTO.getTocken()에서 생성한 토큰과 HttpCookie에 저장할 설정을 정의합니다. 그리고 난 후 HttpServletResponse에 생성한 쿠키를 .addHeader()를 사용해 헤더에 담아 클라이언트 측으로 보냅니다.
- 클라이언트 측으로 성공 메시지와 결과를 ApiResponse.success()로 감싸서 응답합니다.
@PostMapping("/signin")
public ResponseEntity<?> signIn(
@RequestBody LoginReqDTO request,
HttpServletResponse response) {
// 서비스로직
LoginResDTO responseDTO = authService.signIn(request);
// String token = authService.signIn(request);
// Jwt를 HttpOnly 쿠키에 저장
ResponseCookie cookie = ResponseCookie.from("JWT", responseDTO.getToken())
.httpOnly(true)
.secure(true)
.path("/")
.maxAge(24 * 60 * 60)
.sameSite("Strict")
.build();
response.addHeader("Set-Cookie", cookie.toString());
// 성공메시지
String message = messageProvider.getMessage(AuthSuccessCode.AUTH_LOGIN_SUCCESS.getMessage());
// 응답
return ResponseEntity
.status(AuthSuccessCode.AUTH_LOGIN_SUCCESS.getHttpStatus())
.body(ApiResponse.success(
AuthSuccessCode.AUTH_LOGIN_SUCCESS,
message,
responseDTO.getUsername()));
}
# AuthService
- userRepository.findByUsername(request.getUsername())으로 아이디가 유효한지 확인후 User 객체를 생성합니다. 아이디가 없다면 UserErrorCode.USER_NOT_FOUND 예외를 던집니다.
- 생성한 User 객체의 비밀번호와 요청받은 비밀번호를 !passwordEncoder.matches()를 사용하여 일치한지 체크하고 동일하지 않다면 UserErrorCode.INVALID_PASSWORD 예외를 던집니다.
- 사용자의 상태가 ACTIVE 인지 체크를 합니다. 만약에 상태가 ACTIVE가 아니라면 현재 사용자의 상태에 관련된 예외를 던집니다.
- user.setLastLoginDate(LocalDateTime.now())를 사용하여 마지막 로그인 시간을 저장한 후 userRepository.save(user)를 통해 DB에 마지막 로그인 시간을 저장합니다.
- jwtTokenProvider.generateToken(user)을 사용하여 로그인한 사용자의 정보를 토대로 토큰을 생성하여 String token으로 저장합니다.
- Controller 계층으로 user, token을 기반으로 LoginResDTO 객체를 생성하여 반환합니다.
@Transactional
public LoginResDTO signIn(LoginReqDTO request) {
// 사용자 유효 검사
User user = userRepository.findByUsername(request.getUsername())
.orElseThrow(() -> new BaseException(UserErrorCode.USER_NOT_FOUND));
// request와 DB의 password가 동일한지 체크
if (!passwordEncoder.matches(request.getPassword(), user.getPassword())) {
throw new BaseException(UserErrorCode.INVALID_PASSWORD);
}
// 사용자의 상태가 ACTIVE인지 체크
if (user.getStatus() == UserStatus.INACTIVE) {
throw new BaseException(UserErrorCode.USER_STATUS_INACTIVE);
} else if (user.getStatus() == UserStatus.SUSPENDED) {
throw new BaseException(UserErrorCode.USER_STATUS_SUSPENDED);
} else if (user.getStatus() == UserStatus.DELETED) {
throw new BaseException(UserErrorCode.USER_STATUS_DELETED);
}
// 마지막 로그인 시간 저장
user.setLastLoginDate(LocalDateTime.now());
userRepository.save(user);
// 토큰 생성
String token = jwtTokenProvider.generateToken(user);
// 반환
return new LoginResDTO(user, token);
}
# UserRepository
- username으로 사용자 전체 엔티티를 조회하는 Optional<User> findByUsername(String username) 메서드 생성
// username으로 사용자 전체 엔티티 조회
Optional<User> findByUsername(String username);
< 공용: 로그아웃 >
# LogoutResDTO
- 로그아웃 응답 DTO 정의
- 사용자 고유번호, 사용자 아이디 (id, username)
- User 엔티티를 파라미터로 받는 생성자 함수 정의
@Getter
public class LogoutResDTO {
private Long id;
private String username;
public LogoutResDTO(User user) {
this.id = user.getId();
this.username = user.getUsername();
}
}
# AuthController
- POST /api/v1/auth/logout 으로 요청합니다.
- 파라미터로 @AuthenticationPrincipal을 사용해 가져온 사용자 정보를 User 객체로 저장합니다. 그리고 HttpServletResponse타입의 빈 객체 response을 생성합니다.
- 제거용 JWT 쿠키를 생성하여 HttpServletResponse타입의 객체에 .addHeader()로 저장합니다.
- Service계층으로 user.getId를 전달합니다.
- 반환받은 결과는 LogoutResDTO 형태로 저장합니다.
- 성공메시지와 반환받은 결과를 ApiResponse.success()로 감싸서 클라이언트 측으로 반환합니다.
@PostMapping("/logout")
public ResponseEntity<?> logout(
HttpServletResponse response,
@AuthenticationPrincipal User user) {
// Jwt 제거
ResponseCookie deleteCookie = ResponseCookie.from("JWT", "")
.httpOnly(true)
.secure(true)
.path("/")
.maxAge(0) // 쿠키 즉시 만료
.sameSite("Strict")
.build();
response.addHeader("Set-Cookie", deleteCookie.toString());
// 서비스로직
LogoutResDTO responseDTO = authService.logout(user.getId());
// 성공메시지
String message = messageProvider.getMessage(AuthSuccessCode.AUTH_LOGOUT_SUCCESS.getMessage());
// 응답
return ResponseEntity
.status(AuthSuccessCode.AUTH_LOGOUT_SUCCESS.getHttpStatus())
.body(ApiResponse.success(
AuthSuccessCode.AUTH_LOGOUT_SUCCESS,
message,
responseDTO));
}
# AuthService
- userRepository.findById(userId)로 사용자를 조회하여 User 객체로 생성합니다. 만약에 없는 사용자라면 UserErrorCode.USER_NOT_FOUND 예외를 던집니다.
- Controller 계층으로 user를 토대로 LogoutResDTO 객체를 생성하여 반환합니다.
/*
* 공용: 로그아웃
*/
public LogoutResDTO logout(Long userId) {
// userId로 사용자 정보 조회
User user = userRepository.findById(userId)
.orElseThrow(() -> new BaseException(UserErrorCode.USER_NOT_FOUND));
// 반환
return new LogoutResDTO(user);
}