[Node.js] 회원가입 이메일 인증 구현

HoonDong_K·2023년 1월 26일
1

[project #1] movie-inner

목록 보기
2/10
post-thumbnail

회원가입 순서

  1. 이메일 기입 (이메일 중복 여부 확인)
  2. 비밀번호 + 비밀번호 확인 (비밀번호 유효성 검사)
  3. 프로필 사진, 닉네임, 성명, 생년월일 기입
  4. 이메일 주소 인증 메일 발송
  • 원래 이메일을 기입하고 그 페이지에서 바로 인증 메일을 전송하여 검사를 하려 하였지만, 유저의 회원가입 편리성을 위하여 정보를 다 작성하고 마지막에 이메일 주소를 인증하는 순서로 변경하였다.

이메일 주소 인증

mailgun을 통해서유저의 이메일 주소로 메일을 발송할 수 있지만 유저의 이메일 주소가 유효한 지 인증할 수 없었기 때문에 새로운 인증 방식을 구현할 필요가 있었다.

그 동안 다른 웹사이트에서 회원가입을 할 때, 내가 받았던 이메일 주소 인증 메일에는 이메일 인증 문구와 함께 버튼이 존재하였고, 버튼을 누르면 자동으로 웹사이트에 접속하며 이메일이 인증되는 과정을 거쳤다.

우리는 이 방식을 채택하여 구현하기로 하였다.

인증 절차

  1. 유저는 자신의 email 을 서버로 전송하면 서버는 email과 만료 시간을 합쳐 key값을 생성하고 DB에 저장한 뒤, 유저에게 반환한다.
  • 만료 시간 = 값이 전송된 시각 + 5분
new Date(Date.now() + 60 * 1000 * 5)

  1. 유저가 사이트로부터 받은 key값과 email을 다시 전송해주면 서버는 DB에 저장된 email에 해당하는 key와 대조하여 이메일 인증 결과를 반환한다. 하지만 유저가 재전송하는 시각이 만료 시간을 넘으면 이메일 주소는 유효하지 않다고 판단한다.

실제 적용

실제 구현을 위한 기본적인 설계는 완성되었고, 사이트 목적에 맞게 변형시킬 수 있어야 하였다.

  1. key값 생성
    emailexpiredDate를 합쳐 고유한 key값을 만들 수 있는 해시 함수가 필요하였고 이를 위해 md5를 채택하였다.
    ( https://www.npmjs.com/package/md5)

  2. 유저의 key값 재전송
    유저는 서버로부터 key값을 전달받고, 이를 다시 서버에 전송하여 이메일 인증 여부를 요청해야 한다. 이 과정을 위해 유저의 이메일로 인증 요청 버튼을 전송하고 버튼의 링크 URL에는 key값을 query parameter 로 담아놓은다. 결국 유저는 자신의 이메일을 기반으로 생성된 유일한 key를 인증 버튼에 내장되어 이메일로 받게 되고, 버튼을 누름으로써 자동으로 서버에 key를 전송하게 된다.

적용 코드

유저의 이메일 주소로 key가 담긴 버튼을 전송

const emailVerifyLink = async (
    params: { email: string; type: string },
    connection: DbConnection
) => {
    try {
        const { email, type } = params
        //email hash화로 key값 생성
        const expiredDate = new Date(Date.now() + 60 * 1000 * 5) //만료기간 5분
        const hashedEmailFull = md5(email + expiredDate)
        const hashedEmail = hashedEmailFull.substring(0, 12)
        
        // 이메일 등록 여부 파악
        const getResponse = await connection.run(
            `SELECT COUNT(*) AS count FROM user_info WHERE email=?`,
            [email]
        )
        const { count } = getResponse[0]
        if (count > 0) throw "E0000"
      	// 이메일 전송
        else {
            MAILGUN.senVerifyEmail(hashedEmail, email, type)
            //이메일 정보 및 만료 기한 저장
            await connection.run(
                `INSERT INTO email_verify(type,email,email_code,expired_date) VALUES(?,?,?,?)`,
                [type, email, hashedEmail, expiredDate]
            )
        }
    } catch (e: any) {
        paramsErrorHandler(e)
    }
    return {
        status: 201,
        data: {
            success: true,
            message: "이메일로 링크 발송 성공",
        },
    }
}

그리고 유저의 이메일로 발송된 버튼을 누르게 되면 이메일 검증 API가 동작한다.

const checkEmailLink = async (
   params: { key: string; type: string }, //query
   connection: DbConnection
) => {
   let isVerified = false
   try {
       const { key, type } = params
       // key에 해당하는 만료 기한을 가져옴
       const response = await connection.run(
           `SELECT expired_date FROM email_verify WHERE email_code=? AND type=?`,
           [key, type]
       )
       // 존재하지 않을 시 에러
       if (!response[0]) {
           throw "E0002"
       }
	
       // 만료 기한과 현재 시각을 비교
       const { expired_date: expiredDate } = response[0]
       const intExpiredDate = expiredDate.getTime()
       const nowDate = new Date().getTime()
       isVerified = nowDate > intExpiredDate ? false : true
   } catch (e: any) {
       paramsErrorHandler(e)
   }
   return {
       status: 200,
       data: { isVerified },
   }
}

mailgun으로 이메일 전송하기

profile
코드 한 줄이 나를 증명하는 개발자

0개의 댓글