티스토리 뷰

웹 개발/SpringBoot

[String Boot] email 인증

스톤승현 2022. 11. 2. 16:21

- DB 테이블 생성

CREATE SCHEMA `study_member`;

CREATE TABLE `study_member`.`users`
(
    `email`             VARCHAR(50)  NOT NULL,
    `password`          VARCHAR(128) NOT NULL,
    `nickname`          VARCHAR(10)  NOT NULL,
    `name`              VARCHAR(5)   NOT NULL,
    `contact`           VARCHAR(12)  NOT NULL,
    `address_postal`    VARCHAR(6)   NOT NULL,
    `address_primary`   VARCHAR(100) NOT NULL,
    `address_secondary` VARCHAR(100) NOT NULL,
    `registered_on`     DATETIME     NOT NULL DEFAULT NOW(),
    CONSTRAINT PRIMARY KEY (`email`),
    CONSTRAINT UNIQUE (`nickname`),
    CONSTRAINT UNIQUE (`contact`)
);

 

CREATE TABLE `study_member`.`email_auths`
(
    `index`        INT UNSIGNED NOT NULL AUTO_INCREMENT,
    `email`        VARCHAR(50)  NOT NULL,
    `code`         VARCHAR(6)   NOT NULL,
    `salt`         VARCHAR(128) NOT NULL,
    `created_on`   DATETIME     NOT NULL DEFAULT NOW(),
    `expires_on`   DATETIME     NOT NULL,
    `expired_flag` BOOLEAN      NOT NULL DEFAULT FALSE,
    CONSTRAINT PRIMARY KEY (`index`)
);

 

 

- UserEntity.java

package dev.shlee.studymemberbbs.entities.member;

import java.util.Date;
import java.util.Objects;

public class UserEntity {

    private String email;

    private String password;

    private String nickname;

    private String name;

    private String contact;

    private String address_postal;

    private String address_primary;

    private String address_secondary;

    private String registered_on;

    private Date registeredOn;



    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getNickname() {
        return nickname;
    }

    public void setNickname(String nickname) {
        this.nickname = nickname;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getContact() {
        return contact;
    }

    public void setContact(String contact) {
        this.contact = contact;
    }

    public String getAddress_postal() {
        return address_postal;
    }

    public void setAddress_postal(String address_postal) {
        this.address_postal = address_postal;
    }

    public String getAddress_primary() {
        return address_primary;
    }

    public void setAddress_primary(String address_primary) {
        this.address_primary = address_primary;
    }

    public String getAddress_secondary() {
        return address_secondary;
    }

    public void setAddress_secondary(String address_secondary) {
        this.address_secondary = address_secondary;
    }

    public String getRegistered_on() {
        return registered_on;
    }

    public void setRegistered_on(String registered_on) {
        this.registered_on = registered_on;
    }

    public Date getRegisteredOn() {
        return registeredOn;
    }

    public void setRegisteredOn(Date registeredOn) {
        this.registeredOn = registeredOn;
    }

    @Override
    public boolean equals(Object o) { //equals 재정의 기본키만 합니다
        if (this == o) return true; // 스택값이 같으면 참
        if (o == null || getClass() != o.getClass()) return false; //NULL 이거나 객체의 클래스랑 다르다면 false
        UserEntity that = (UserEntity) o; //나랑은 다른데 같은 객체이다. 형변환
        return Objects.equals(email, that.email); // 같은가의 여부...
    }

    @Override
    public int hashCode() {
        return Objects.hash(email);
    }
}

- 게터세터 설정해주고 equals, hash는 기본키만 설정해준다. 

- MemberMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="dev.shlee.studymemberbbs.mappers.IMemberMapper">
    <select id="selectUserByEmail"
            resultType="dev.shlee.studymemberbbs.entities.member.UserEntity">
        SELECT `email`             AS `email`,
               `password`          AS `password`,
               `nickname`          AS `nickname`,
               `name`              AS `name`,
               `contact`           AS `contact`,
               `address_postal`    AS `addressPostal`,
               `address_primary`   AS `addressPrimary`,
               `address_secondary` AS `addressSecondary`,
               `registered_on`     AS `registeredOn`
        FROM `study_member`.users
        WHERE BINARY `email` = #{email}
        LIMIT 1
    </select>
</mapper>

- MemberService.java

1
@Service(value = "dev.shlee.studymemberbbs.services.MemberService")
public class MemberService {
    private final IMemberMapper memberMapper;//변수로 만들때 I는 빼고 만드는게 국룰

    @Autowired
    public MemberService(IMemberMapper memberMapper) {
        this.memberMapper = memberMapper;
    }

    @Transactional
    public void sendEmailAuth(UserEntity user) { //UserEntity에게 이메일 검증을 요청하겠다
        //1 0
        //2 0
        //3 x
        //하나라도 안되면 위에거 전부취소

    }
}
// 트랜잭션 적용하기
=============================================================================================
2
package dev.shlee.studymemberbbs.services;

import dev.shlee.studymemberbbs.entities.member.UserEntity;
import dev.shlee.studymemberbbs.enums.CommonResult;
import dev.shlee.studymemberbbs.enums.member.SendEmailAuthResult;
import dev.shlee.studymemberbbs.interfaces.IResult;
import dev.shlee.studymemberbbs.mappers.IMemberMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service(value = "dev.shlee.studymemberbbs.services.MemberService")
public class MemberService {
    private final IMemberMapper memberMapper;//변수로 만들때 I는 빼고 만드는게 국룰

    @Autowired
    public MemberService(IMemberMapper memberMapper) {
        this.memberMapper = memberMapper;
    }
//1안
    @Transactional
    public Enum<? extends IResult> sendEmailAuth(UserEntity user) { //UserEntity에게 이메일 검증을 요청하겠다. 반드시 IResult를 구현하거나 상속받고 있어야한다.
        return CommonResult.SUCCESS; //Enum은 name메서드를 가지고 있기 때문에 name메서드를 안만들어도 된다.

    }
}
// 2안
//    @Transactional
//    public IResult sendEmailAuth(UserEntity user) { //UserEntity에게 이메일 검증을 요청하겠다. 반드시 U
//        return CommonResult.SUCCESS; //interface에 name메서드를 넣어줘야함
//
//    }
==========================================================================================================
//3 
package dev.shlee.studymemberbbs.services;

import dev.shlee.studymemberbbs.entities.member.EmailAuthEntity;
import dev.shlee.studymemberbbs.entities.member.UserEntity;
import dev.shlee.studymemberbbs.enums.CommonResult;
import dev.shlee.studymemberbbs.enums.member.SendEmailAuthResult;
import dev.shlee.studymemberbbs.interfaces.IResult;
import dev.shlee.studymemberbbs.mappers.IMemberMapper;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;


import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Date;

@Service(value = "dev.shlee.studymemberbbs.services.MemberService")
public class MemberService {
    private final IMemberMapper memberMapper;//변수로 만들때 I는 빼고 만드는게 국룰

    @Autowired
    public MemberService(IMemberMapper memberMapper) {
        this.memberMapper = memberMapper;
    }

    @Transactional
    public Enum<? extends IResult> sendEmailAuth(UserEntity user, EmailAuthEntity emailAuth) throws NoSuchAlgorithmException { //UserEntity에게 이메일 검증을 요청하겠다. user은 controller에서 받아온다.
        UserEntity existingUser = this.memberMapper.selectUserByEmail(user.getEmail());
        if (existingUser != null) {
            return SendEmailAuthResult.EMAIL_DUPLICATED; // null이 아니면 값이 있다는 것
        }
        String authCode = RandomStringUtils.randomNumeric(6); //6자의 랜덤한 문자열 가져오기
        String authSalt = String.format("%s%s%f%f",
                user.getEmail(),
                authCode,
                Math.random(),
                Math.random());

        StringBuilder authSaltHashBuilder = new StringBuilder();
        MessageDigest md = MessageDigest.getInstance("SHA-512");
        md.update(authSalt.getBytes(StandardCharsets.UTF_8));

        for (byte hashByte : md.digest()) {
            authSaltHashBuilder.append(String.format("%02x", hashByte));
        }
        authSalt = authSaltHashBuilder.toString();

        Date createOn = new Date();
        Date expiresOn = DateUtils.addMinutes(createOn, 5);

        emailAuth.setCode(authCode);
        emailAuth.setSalt(authSalt);
        emailAuth.setCreatedOn(createOn);
        emailAuth.setExpiresOn(expiresOn);
        emailAuth.setExpired(false);
        if (this.memberMapper.insertEmailAuth(emailAuth) == 0) {
            return CommonResult.FAILURE;
        }


        return CommonResult.SUCCESS;

    }
}

- MemberController 

    @RequestMapping(value = "/email",
            method = RequestMethod.POST,
            produces = MediaType.APPLICATION_JSON_VALUE) //응답결과를 json으로 해석 조언
    @ResponseBody // 문자열 그대로 나온다.
    public String postEmail(UserEntity user, EmailAuthEntity emailAuth) throws NoSuchAlgorithmException { // 엔티티에서 가져온다.
        Enum<?> result = this.memberService.sendEmailAuth(user, emailAuth);

        return result.name().toLowerCase();
    }
}

무조건 기억해야하는 로직

package dev.shlee.studymemberbbs.interfaces;

public interface IResult {
}

- IResult를 만들어주어야 열거형형태인 CommonResult랑 SendEmailAuthResult를 Service에서 상속받아서 두 개 만을 사용할 수 있다. 

 

- CommonResult.java

package dev.shlee.studymemberbbs.enums;

import dev.shlee.studymemberbbs.interfaces.IResult;

public enum CommonResult implements IResult {
    FAILURE, // 실패?
    SUCCESS // 인증 번호를 전송하였습니다. 5분 이내에 입력해 주세요.

    //name메서드를 구현하고 있어서 안 터짐.
}

- SendEmailAuthResult.java

package dev.shlee.studymemberbbs.enums.member;

import dev.shlee.studymemberbbs.interfaces.IResult;

public enum SendEmailAuthResult implements IResult { // member 메서드에 있는 SnedEmailAuth의 결과
    EMAIL_DUPLICATED // 이미 사용중인 이메일 입니다.
}

 

- 의존성 추가

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.12.0</version>
</dependency>

- MemberMapper.xml


<insert id="insertEmailAuth"
        useGeneratedKeys="true"
        keyColumn="index"
        keyProperty="index"
        parameterType="dev.shlee.study_web.entities.member.EmailAuthEntity">
    INSERT INTO `study_member`.`email_auths` (`email`, `code`, `salt`, `created_on`, `expires_on`, `expired_flag`)
    VALUES (#{email}, #{code}, #{salt}, #{createdOn}, #{expiresOn}, #{isExpired})

</insert>

insert 추가 

 

- 결과

- 페이지에서 이메일을 입력하면 이렇게 나온다

 

구현한 페이지!!
이렇게 이메일을 입력해서 인증번호 전송을 하면
DB에 값이 저장되는 것을 볼 수 있다!!

진짜 너어어어ㅓ어ㅓ어어어ㅓ어어어ㅓㅇ어무 어렵다! 

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2026/04   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30
글 보관함