HJ CHAT 로그인/회원가입 API 작성
2024. 12. 13. 18:46ㆍTIL
Branch
Security, member, chat 등 각각의 기능에 대해서 branch로 나누어 작업후 merge하는 식으로 진행
Security
Security 관련 부분은 이전에 사용했던 파일을 그대로 가져와 토큰 안에 들어가는 값들만 현재 프로젝트에 맞게 수정
Member
작성해둔 ERD를 바탕으로 ENTITY 작성(구글,카카오 로그인을 통한 소셜 로그인은 추후 확장 예정)
@Entity
@Table(name = "members")
class MemberEntity(
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Long = 0,
@Column(name="userName", unique = true, nullable = false)
val userName: String,
@Column(name="email", unique = true, nullable = false)
val email: String,
@Column(name="탈퇴_유무")
val isDeleted: Boolean = false,
@Column(name="생성_날짜", nullable = false)
val createdAt: LocalDate = LocalDate.now(),
@Column(name="탈퇴_시간")
val deletedAt: LocalDate? = null,
@Column(name="회원_상태")
val status: String?,
@Column(name="유저_role")
val memberRole: String,
)
Mysql 연결 (개발 단계에서는 local 서버를 이용하며 추후에 배포할때 AWS RDS를 사용할 예정)
회원가입, 로그인 API 작성
토큰 확인
토큰이 정상적으로 발급되는것을 확인했으니
login api에서 AccessToken을 헤더에, RefreshToken을 쿠키에 담기도록 코드를 수정
@PostMapping("/login")
fun login(@RequestBody request: LoginRequest, response: HttpServletResponse): ResponseEntity<String> {
val tokenResponse = oAuthService.login(request)
// ACCESS TOKEN을 헤더에 담아서 반환
val headers = HttpHeaders()
headers.add("Authorization", "Bearer ${tokenResponse.accessToken}")
// REFRESH TOKEN을 쿠키에 저장
val refreshTokenCookie = Cookie("refreshToken", tokenResponse.refreshToken).apply {
isHttpOnly = true
secure = true
path = "/"
}
response.addCookie(refreshTokenCookie)
return ResponseEntity.ok()
.headers(headers)
.body("토큰 발급 성공")
}
개발자 도구를 통해서 RefreshToken이 쿠키에 담겨져 있는것을 확인할 수 있으며
authorization header에는 AccessToken이 정상적으로 잘 담겨져있는것을 확인할 수 있다.
이메일 인증 추가
@Transactional
fun signUp(request: SignUpRequest): String {
if (oAuthRepository.existsByUserName(request.username))
throw DuplicateUsernameException("이미 존재하는 닉네임")
if (oAuthRepository.existsByEmail(request.email))
throw DuplicateEmailException("존재하는 이메일")
if (request.password != request.confirmPassword)
throw PasswordMismatchException("비밀번호와 확인 비밀번호가 일치하지 않습니다.")
val imsiMember = emailVerifyRepository.save(
NotVerifyMemberEntity(
userName = request.username,
email = request.email,
password = request.password,
)
)
val imsiToken =jwtTokenManager.generateTokenResponse(imsiMember.id, MemberRole.USER.name).accessToken
emailService.sendVerificationEmail(request.email, imsiToken)
return "이메일로 인증코드를 발송하였습니다."
}
fun verifyEmail(token: String): String {
// 이메일 인증을 위해 받은 token을 검증
val parsedToken = jwtTokenManager.validateToken(token).getOrElse {
throw IllegalArgumentException("유효하지 않은 토큰입니다. 다시 확인해주세요.")
}
val memberId = parsedToken.body.subject.toLong()
val member = emailVerifyRepository.findById(memberId).orElseThrow{
IllegalArgumentException("해당 ID의 인증 대기 유저를 찾을 수 없습니다.")
}
oAuthRepository.save(
MemberEntity(
userName = member.userName,
email = member.email,
password = passwordEncoder.encode(member.password),
status = "ACTIVE",
memberRole = "USER",
)
)
emailVerifyRepository.delete(member)
return "이메일 인증이 완료되었습니다."
}
별도의 테이블을 만들어 처음 회원가입을 할때 인증되지 않은 유저 테이블에 저장을 하고 이메일 인증을 완료하면 원래의 유저테이블에 저장하는 형태를 취한다.
1시간이 지나도 인증이 되지 않은 데이터에 대해서는 삭제 로직을 구현하지 않았다. (스케쥴러 등)
'TIL' 카테고리의 다른 글
Sᴘʀɪɴɢ ꜱᴇᴄᴜʀɪᴛʏ와 Sᴘʀɪɴɢ GʀᴀᴘʜQL 통합 (1) | 2024.12.17 |
---|---|
GraphiQL (0) | 2024.12.16 |
실시간 채팅 서비스 API 시스템 아키텍처 및 설계 (0) | 2024.12.12 |
𝐆𝐫𝐚𝐩𝐡𝐐𝐋 𝐕𝐒 𝐑𝐄𝐒𝐓 𝐀𝐏𝐈 (0) | 2024.12.11 |
공공데이터 활용 프로젝트 마무리 및 제출 (1) | 2024.12.09 |