Project kakao Day3 이메일 인증 절차

김지원·2022년 6월 24일
0

WebDevelop

목록 보기
10/21

이메일 인증 절차

1. Email 주소를 입력한다. → 인증요청이 들어가게 된다. 

                           → 1-1 정규화 (정규식 확인)  
                             1-2 중복 확인 (회원정보) 
                       ↓   ← 1-3 인증번호 발송 (6자리 숫자 코드 사용) 
                       
2. 위의 3가지가 다 되었다. →  인증 Code 받는다. → 인증버튼 누름
							→ 2-1 인증번호 확인

클라이언트가 인증번호를 받아서 다시 보내온 인증번호가 맞는 인증번호인지 알 수 없다. 보내기만 했지 따로 기록을 해놓지 않았기 때문이다.
그래서 DB에 인증번호를 집어 넣어야한다.

만약 누군가가 사이트에서 회원가입을 진행중인데 실시간으로 화면 해킹을 당하고 있다고 가정하자. 그렇게 되면 해커가 사용자의 인증번호와 이메일 주소를 알게 되어 해커도 인증을 할 수 있게 된다.
그래서 '토큰' 이란걸 만든다.

인증 번호 | 이메일 | 토큰

  • 토큰 : SHA512알고리즘 사용, 128자로 랜덤하게 만들것임.

발송이 이루어질때 인증번호, 이메일, 토큰이 DB에 들어가야하고 인증번호는 이메일로 전송이 되야하고 토큰은 xhr의 응답으로써 (xhr을 통해) 클라이언트 브라우저로 돌아가야한다. 그렇다면 자바스크립트로 해당 토큰을 받아올 수 있다. 그 가져온 토큰을 어딘가에 둬야한다. 보여지면 안되기 때문에 눈에 보이지 않는 input type을 사용한다.
input type="hidden" value="token" 이렇게 사용할 것이다. 인증번호확인을 하는 순서에서

사용자가 코드 6자리 입력하고 인증버튼을 누르게 되면 서버로 여러개의 데이터가 넘어오는데 꼭 있어야하는건 인증코드, 토큰, 이메일이 있어야한다. 이 3개에 해당하는 레코드가 있는지 없는지 확인하고 인증을 시켜주던지 말던지 하면 된다.


-> index.unsigned.html 이메일 인증 추가

<div class="step email">
            <span class="title">카카오계정으로 사용할<br>이메일 주소를 입력해 주세요.</span>
            <label class="email-input-container">
                <input class="email-input invalid" maxlength="50" name="email" placeholder="이메일 주소 입력" type="email">
                <input class="code-request-button" disabled name="emailCodeRequestButton" type="button" value="인증요청">
                <span class="warning">카카오계정 이메일을 입력해 주세요.</span>
            </label>
            <label class="code-input-container">
                <input class="code-input" maxlength="6" name="emailCode" placeholder="인증번호 입력" type="text">
                <input class="code-verify-button" name="emailCodeVerifyButton" type="button" value="인증">
                <span class="warning">인증번호를 입력해 주세요.</span>
            </label>
            <ul class="info">
                <li>입력한 이메일 주소로 인증번호가 발송됩니다.</li>
                <li>인증메일을 받을 수 있도록 자주 쓰는 이메일 주소를 입력해 주세요.</li>
            </ul>
            <input class="button" disabled name="emailNext" type="button" rel="emailNext" value="다음">
        </div>

-> index.unsigned.js 이메일 인증 추가

// 동의 버튼을 클릭했을 때 일어날 일들에 대해 진행.
// 이메일 인증 쪽으로 넘어가게 할 것.
Element.RegisterForm.Step.Terms.Next.getElement().addEventListener('click', () => {
    Element.RegisterForm.Step.Terms.hide();// 약관 동의를 숨긴다.
    Element.RegisterForm.Step.Email.show();
    Element.RegisterForm.Progress.setValue(20);// 위에 프로그레스 20퍼센트만 주는 것.
    const emailInput = Element.RegisterForm.getElement()['email'];
    emailInput.value = '';
    emailInput.focus();
});
// Element.RegisterForm.getElement()['email'] //이렇게 적으면 name이 email인 input이 잡힌다

Element.RegisterForm.getElement()['email'].addEventListener('keyup', e => {
    const emailRegex = new RegExp('^(?=.{10,50})([0-9a-z]{4,})@([0-9a-z]{3,})\\.([a-z]{2,15})(\\.[a-z]{2})?$');
    if (emailRegex.test(e.target.value)) {
        e.target.classList.remove('invalid'); // e.target이 Element.RegisterForm.getElement()['email'] 이 자체이다. 즉 input임 //정규식이 맞으면 remove
        Element.RegisterForm.getElement()['emailCodeRequestButton'].removeAttribute('disabled');
    } else {
        e.target.classList.add('invalid');// 정규식이 틀리면 warning 태그인 카카오계정 이메일을 입력해 주세요. 가 나옴.
        Element.RegisterForm.getElement()['emailCodeRequestButton'].setAttribute('disabled', 'disabled');         // 올바른 이메일일 때 인증요청 버튼이 살아나고 올바르지 않았을 때에는 주석으로 처리가 될 것
    }
});

// 인증 요청을 눌렀을 때
Element.RegisterForm.getElement()['emailCodeRequestButton'].addEventListener('click', e => {
    const emailInput = Element.RegisterForm.getElement()['email'];
    emailInput.setAttribute('disabled', 'disabled');
    e.target.setAttribute('disabled', 'disabled');// 이메일을 전송하는 과정에 이메일 인풋과 버튼을 활성화 녹음..
    const formData = new FormData();
    const xhr = new XMLHttpRequest();
    formData.append('email', e.target.value);// 서버에 보낸 데이터 : 이메일
    xhr.open('POST', 'user/request-email-code');
    xhr.onreadystatechange = () => {
        if (xhr.readyState === XMLHttpRequest.DONE) {
            if (xhr.status >= 200 && xhr.status < 300) {
                const responseJson = JSON.parse(xhr.responseText);
                let message = null;
                switch (responseJson['result']) {
                    case 'SUCCESS':
                        emailInput.setAttribute('disabled', 'disabled');
                        e.target.setAttribute('disabled', 'disabled');
                        Element.RegisterForm.Step.Email
                            .getElement()
                            .querySelector('.code-input-container').classList
                            .add('visible');
                        const emailCodeInput = Element.RegisterForm.getElement()['emailCode'];
                        emailCodeInput.value = '';
                        emailCodeInput.focus();
                        break;
                    case 'DUPLICATE':
                        message = '이미 사용 중인 이메일 입니다.';
                        break;
                    default:
                        message = '잠시 후 다시 시도해 주세요.';
                }
                if (message !== null) {
                    emailInput.parentNode.querySelector(':scope > .warning').innerText = message;
                    emailInput.classList.add('invalid');
                    emailInput.removeAttribute('disabled');
                    emailInput.focus();
                    emailInput.select();
                    e.target.removeAttribute('disabled');
                }
            } else {
                emailInput.parentNode.querySelector(':scope > .warning').innerText = '잠시 후 다시 시도해 주세요.';
                emailInput.classList.add('invalid');
                emailInput.removeAttribute('disabled');
                emailInput.focus();
                emailInput.select();
                e.target.removeAttribute('disabled');
            }
        }
    };
    xhr.send(formData);
});


-> UserController 생성

  • StandardController 상속받고 StandardController 얘가 필요로하는 생성자 호출
  • @ResponseBody JSON으로 돌아갈 것이기 때문에 사용.
  • UserService 만들기만 하고 UserService를 멤버변수로 추가.

-> 다시 UserService 돌아와서

  • putEmailCode 메서드 생성, 얘가 반환해주는 것은 결과랑 토큰이다.

-> 테이블이랑 관계없는 dtos패키지, memeber패키지 생성.

-> kakao_member.email_codes 테이블 생성

  • ua는 UserAgent이다. 128자 라는 것은 SHA512을 이용해서 Hashing 한다는 의미인데 굳이 저렇게 하는 이유는 기존에 진행하던 브라우저를 그대로 진행해야된다는 뜻이다. bbs-basic에서 했던 링크를 통해 이메일 인증할 때에는 pc로 회원가입을 진행하고 핸드폰으로 인증을 할 가능성이 있었는데 이번에는 그러한 가능성이 없기 때문에 (=회원가입 중간에 브라우저가 바뀔일이 없다.) 그래서 ua도 맞춰야한다.

-> EmailCodeEntity

-> UserController

  • @RequestParam 으로 받는 것이 아닌 EmailCodeEntity 로 변경해준다.
  • UserAgent 넣을 것이기 때문에 HttpServletRequest request 추가.

-> UserService

  • String email -> EmailCodeEntity emailCodeEntity 변경

-> UserController

  • HttpServletRequest request 값 초기화.
	 String ua = request.getHeader("User_Agent");
     if(ua==null) {
         ua="";
     }
     emailCodeRequestVo.setUa(ua);

-> vos 패키지 member 패키지 EmailCodeRequestVo 추가

-> UserService 정규식 추가

-> enums 패키지 member 패키지 EmailCodeRequestResult 추가

-> interface 패키지 IResult 추가

-> EmailCodeRequestVo 추가

  • implements IResult<EmailCodeRequestResult>
  • setResult 타입 EmailCodeRequestResult

< 중복검사를 위한 로직 >
-> mappers 패키지 IUserMapper 추가

-> UserMapper.xml 추가

-> UserService

profile
Software Developer : -)

0개의 댓글