SPRING/PROJECT

[๊ตฌํ˜„] ์Šคํ”„๋ง์œผ๋กœ ์ด๋ฉ”์ผ ์ธ์ฆ ์ฝ”๋“œ ๋ฐœ๊ธ‰, ์ธ์ฆํ•˜๊ธฐ

ozllzL 2021. 12. 12. 22:15

๊ณต๋ถ€ํ•˜๋ฉด์„œ ๋งŒ๋“ค์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ํ‹€๋ฆฐ ๋ถ€๋ถ„์ด๋‚˜ ๋” ์ข‹์€ ๋ฐฉ๋ฒ•์ด ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค!

 

๊ตฌํ˜„ ํ•  ๋‚ด์šฉ

1)

  • ๋ฉ”์ผ ์ธ์ฆ ์ฝ”๋“œ๋ฅผ ๋งŒ๋“ ๋‹ค.
  • ํ•ด๋‹น ๋ฉ”์ผ๋กœ ์ธ์ฆ ์ฝ”๋“œ๋ฅผ ๋ณด๋‚ธ๋‹ค.

2)

  • ๋ฉ”์ผ๋กœ ์˜จ ์ธ์ฆ ์ฝ”๋“œ๋ฅผ ์ž…๋ ฅํ•œ๋‹ค.
  • ๋ฉ”์ผ๊ณผ ์ธ์ฆ ์ฝ”๋“œ ์ผ์น˜ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•œ๋‹ค.

 

1. ์•„์ด๋”” ๋งŒ๋“ค๊ธฐ

๋‚˜๋Š” Gmail SMTP Server๋ฅผ ์ด์šฉํ•  ๊ฒƒ์ด๋‹ค.

๊ฐœ์ธ ์ด๋ฉ”์ผ์„ ์‚ฌ์šฉํ•˜๊ธฐ๋Š” ์ข€ ๊ทธ๋ ‡๊ธฐ์— ์ƒˆ๋กœ์šด ๊ณ„์ •์„ ํ•˜๋‚˜ ๋” ๋งŒ๋“ค๊ฒƒ์ด๋‹ค.

๊ณ„์ •์˜ ๋ณด์•ˆ์ด ๋‚ฎ์€ ์•ฑ์˜ ์•ก์„ธ์Šค๋ฅผ ํ—ˆ์šฉํ•ด ์ฃผ์–ด์•ผ ํ•œ๋‹ค๊ณ  ํ•œ๋‹ค.

 

2. Gmail SMTP Server ์„ค์ •

build.gradleํŒŒ์ผ์˜ dependencies์— ๋‹ค์Œ ๋ฌธ์žฅ์„ ์ถ”๊ฐ€ํ•ด์ค€๋‹ค.

implementation 'org.springframework.boot:spring-boot-starter-mail'

 

application.propertiesํŒŒ์ผ์— ๋‹ค์Œ ๋ฌธ์žฅ์„ ์ถ”๊ฐ€ํ•ด์ค€๋‹ค.

spring.mail.host=smtp.gmail.com
spring.mail.port=587
spring.mail.username=(email)
spring.mail.password=(password)
spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.properties.mail.smtp.auth=true

email, password๋Š” ๋ณธ์ธ ๊ฒƒ ๋„ฃ์œผ๋ฉด ๋œ๋‹ค.

 

3. ์ธ์ฆ ์ฝ”๋“œ ๋„๋ฉ”์ธ ์—”ํ‹ฐํ‹ฐ ๋งŒ๋“ค๊ธฐ

verifycode๋Š” ์ฝ”๋“œ๊ฐ’๊ณผ ์ฝ”๋“œ์˜ ์ด๋ฉ”์ผ๋กœ ์ด๋ฃจ์–ด์ ธ ์žˆ๋‹ค.

์ฝ”๋“œ๋Š” ์ž๋™์ƒ์„ฑ์ด๋ฉฐ ์ด๋ฉ”์ผ๊ณผ ์ฝ”๋“œ๊ฐ€ ๋งž๋Š”์ง€ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•จ์ด๋‹ค.

@Getter
@Entity
@Table
@AllArgsConstructor
@NoArgsConstructor
public class VerifyCode extends Timestamped{

    @Id
    @Column(name = "code")
    @GeneratedValue(generator = RandomGenerator.generatorName)
    @GenericGenerator(name = RandomGenerator.generatorName, strategy = "com.moment.CapturedMomentServer.util.RandomGenerator")
    String code;

    @Column(name = "email", unique = true)
    String email;

    public VerifyCode(VerifyCodeDto dto){
        this.email = dto.getEmail();
    }
}

randomgenerator๋Š” ๋‹ค๋ฅธ ๋ถ„์ด ์ธํ„ฐ๋„ท์— ์˜ฌ๋ ค์ฃผ์‹  ์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์˜€๋‹ค.

http://daplus.net/java-%EC%9E%84%EC%9D%98%EC%9D%98-%EC%98%81%EC%88%AB%EC%9E%90-%EB%AC%B8%EC%9E%90%EC%97%B4%EC%9D%84-%EC%83%9D%EC%84%B1%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95%EC%9D%80-%EB%AC%B4%EC%97%87%EC%9E%85/

 

[java] ์ž„์˜์˜ ์˜์ˆซ์ž ๋ฌธ์ž์—ด์„ ์ƒ์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? - ๋ฆฌ๋ทฐ๋‚˜๋ผ

๋‚˜๋Š” ์ฐพ๊ณ  ์žˆ์—ˆ๋‹ค ์˜์‚ฌ ๋‚œ์ˆ˜ ์˜์ˆซ์ž ๋ฌธ์ž์—ด์„ ์ƒ์„ฑํ•˜๋Š” ๊ฐ„๋‹จํ•œ Java ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚ด ์ƒํ™ฉ์—์„œ ๊ทธ๊ฒƒ์€ 500K+์„ธ๋Œ€๋ฅผ ์ดˆ์›”ํ•˜์—ฌ “์•„๋งˆ๋„”๋…์ฐฝ์  ์ธ ๊ณ ์œ  ์„ธ์…˜ / ํ‚ค ์‹๋ณ„์ž๋กœ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค (ํ•„

daplus.net

์ธํ„ฐ๋„ท์— ๋งŽ์ด ๋„๋Š” ์ฝ”๋“œ ๊ฐ™๊ธด ํ•œ๋ฐ ์ด๋Ÿฐ ์ฝ”๋“œ๋ฅผ ์ฐธ๊ณ ํ–ˆ๊ณ  12์ž์˜ ๋žœ๋ค ๋ฌธ์ž๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

UUID๋Š” ๋„ˆ๋ฌด ๊ธธ์–ด์„œ ์‚ฌ์šฉํ•˜๊ฒŒ ๋˜์—ˆ๋‹ค.

 

์ฒ˜์Œ์—๋Š” ์ด๋ฉ”์ผ๋งŒ์„ ์ž…๋ ฅํ•˜๋ฉด ์ฝ”๋“œ๊ฐ€ ์ž๋™์ƒ์„ฑ ๋ฐœ๊ธ‰๋˜์–ด์•ผ ํ•˜๋ฏ€๋กœ DTO๋ฅผ ๋งŒ๋“ค๋„๋ก ํ•˜๊ฒ ๋‹ค.

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class VerifyCodeDto {
    @NotNull
    private String email;   // ํšŒ์› ๋‹‰๋„ค์ž„
}

 

4. ์ปจํŠธ๋กค๋Ÿฌ ๋งŒ๋“ค๊ธฐ

์ธ์ฆ ์ฝ”๋“œ ๋ฉ”์ผ ์ „์†ก ์ปจํŠธ๋กค๋Ÿฌ๋ถ€ํ„ฐ ๋งŒ๋“ค์–ด๋ณด๋„๋ก ํ•˜๊ฒ ๋‹ค.

    @PostMapping(value = "/user/certification")
    public ResponseEntity<HashMap> mailCheck(@RequestBody VerifyCodeDto codeDto){
        
        //์ฝ”๋“œ ์ƒ์„ฑ & ์ €์žฅ
        VerifyCode verifyCode = verifyCodeService.saveCode(codeDto);
        
        //๋ฉ”์ผ ์ „์†ก
        boolean success = mailService.checkEmail(verifyCode);

        HashMap<String, Object> responseMap = new HashMap<>();
        if(success) {
            responseMap.put("status", 200);
            responseMap.put("message", "๋ฉ”์ผ ๋ฐœ์†ก ์„ฑ๊ณต");
            responseMap.put("code" , verifyCode.getCode());
            return new ResponseEntity<HashMap> (responseMap, HttpStatus.OK);
        }
        else{
            responseMap.put("status", 500);
            responseMap.put("message", "๋ฉ”์ผ ๋ฐœ์†ก ์‹คํŒจ");
            return new ResponseEntity<HashMap> (responseMap, HttpStatus.CONFLICT);
        }
    }

verifyCodeService์—์„œ ์ฝ”๋“œ๋ฅผ ์ƒ์„ฑํ•ด ์ €์žฅํ•œ๋‹ค.

๋‹ค์Œ ์ฝ”๋“œ๋ฅผ mailService์—์„œ ์ด๋ฉ”์ผ๋กœ ์ „์†กํ•œ๋‹ค.

 

5. VerifyCodeRepository

@Repository
public interface VerifyCodeRepository extends JpaRepository<VerifyCode, Long> {
    public VerifyCode findByEmail(String email);
    public VerifyCode findByCode(String code);
    public boolean existsByEmail(String email);
    public void deleteByEmail(String email);
}

6. VerifyCodeService

@Service
@Transactional
@AllArgsConstructor
public class VerifyCodeService {

    private final VerifyCodeRepository repository;

    ...

    public VerifyCode saveCode(VerifyCodeDto code){
        if(repository.existsByEmail(code.getEmail()))
            repository.deleteByEmail(code.getEmail());
        return repository.save(new VerifyCode(code));
    }
    ...
}

(์ด๋ฉ”์ผ๋งŒ ๋“ค์–ด์žˆ๋Š”) VerifyCodeDto๋ฅผ ๋ฐ›์•„์„œ

์ธ์ฆ ์ฝ”๋“œ๊ฐ€ ๋ฐœ๊ธ‰๋˜์–ด์žˆ๋Š” ์ด๋ฉ”์ผ์ธ์ง€ ํ™•์ธํ•œ๋‹ค.

๋ฐœ๊ธ‰๋˜์–ด ์žˆ๋‹ค๋ฉด, ๊ทธ ์ธ์ฆ์ฝ”๋“œ๋Š” ์‚ญ์ œํ•œ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ์—ฌํŠผ ๋ฐ›์€ ์ด๋ฉ”์ผ๋กœ new VerifyCode๋ฅผ ๋งŒ๋“ค์–ด์„œ ์ƒˆ ์ธ์ฆ ์ฝ”๋“œ๋ฅผ ์ƒ์„ฑํ•ด์ค€๋‹ค.

 

7. MailService

@Service
@RequiredArgsConstructor
public class MailService {

    private final JavaMailSender javaMailSender;
    private final PasswordEncoder passwordEncoder;

    public boolean checkEmail(VerifyCode verifyCode){

        if(verifyCode.getCode() == null)
            return false;

        SimpleMailMessage simpleMailMessage = new SimpleMailMessage();
        simpleMailMessage.setTo(verifyCode.getEmail());
        simpleMailMessage.setSubject("Captured-Moment ์ด๋ฉ”์ผ ํ™•์ธ ์ฝ”๋“œ");
        simpleMailMessage.setText("์ €ํฌ ์„œ๋น„์Šค์— ๊ฐ€์ž…ํ•ด ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.\n"
        + "์ด๋ฉ”์ผ ํ™•์ธ ์ฝ”๋“œ๋Š” " + verifyCode.getCode() + " ์ž…๋‹ˆ๋‹ค.");

        javaMailSender.send(simpleMailMessage);
        return true;
    }
    ...
}

JavaMailSender๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

To, Subject(์ œ๋ชฉ), ๋ณด๋‚ผ Text๋ฅผ ์„ค์ •ํ•œ๋‹ค.

๋‚ด์šฉ์€ ์ € ์ฝ”๋“œ์™€ ๊ฐ™์ด ์„ค์ •ํ•œ๋‹ค.

 

8. ํ…Œ์ŠคํŠธ

๋‘๊ทผ...โค ์ง„์งœ ์™€์žˆ๋‹ค

 

 

9. ์ปจํŠธ๋กค๋Ÿฌ

๋‹ค์Œ์€ ์ž…๋ ฅ๋ฐ›์€ ์ฝ”๋“œ๊ฐ€ ์ด ์ด๋ฉ”์ผ๊ณผ ๋งž๋Š” ์ฝ”๋“œ์ธ์ง€ ํ™•์ธํ•˜๋Š” ์ปจํŠธ๋กค๋Ÿฌ๋‹ค.

    @GetMapping(value = "/user/check")
    public ResponseEntity<HashMap> mailCheck(@RequestBody VerifyCode verifyCode){

        boolean check = verifyCodeService.check(verifyCode);
        HashMap<String, Object> responseMap = new HashMap<>();

        if(check){
            verifyCodeService.deleteByEmail(verifyCode.getEmail());
            responseMap.put("status", 200);
            responseMap.put("message", "์ธ์ฆ ์„ฑ๊ณต");
            return new ResponseEntity<HashMap> (responseMap, HttpStatus.OK);
        }
        else{
            responseMap.put("status", 401);
            responseMap.put("message", "์ž˜๋ชป๋œ ์ธ์ฆ ์ฝ”๋“œ");
            return new ResponseEntity<HashMap> (responseMap, HttpStatus.CONFLICT);
        }
    }

๋งž๋Š”์ง€ ์ฒดํฌํ•˜๊ณ  ๋งž๋‹ค๋ฉด ์ธ์ฆ์„ฑ๊ณต, ํ‹€๋ฆฌ๋‹ค๋ฉด ์ธ์ฆ ์ฝ”๋“œ๊ฐ€ ํ‹€๋ ธ๋‹ค๋Š” ๋ฉ”์„ธ์ง€๊ฐ€ ๋‚˜์˜จ๋‹ค.

๋˜ํ•œ ์ธ์ฆ์ด ์„ฑ๊ณตํ•œ๋‹ค๋ฉด ํ•ด๋‹น ์ธ์ฆ์ฝ”๋“œ๋Š” ์ง€์›Œ๋ฒ„๋ฆฐ๋‹ค. ๋” ์ด์ƒ ์“ธ๋ชจ๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

 

10. VerifyCodeService

@Service
@Transactional
@AllArgsConstructor
public class VerifyCodeService {

    private final VerifyCodeRepository repository;

    public boolean check(VerifyCode code){
        VerifyCode findCode = repository.findByEmail(code.getEmail());
        if(findCode == null)
            return false;
        else if(code.getCode().equals(findCode.getCode()))
            return true;
        else
            return false;
    }
    
    public void deleteByEmail(String email){
        repository.deleteByEmail(email);
    }
}

์ž…๋ ฅ๋œ ์ด๋ฉ”์ผ๋กœ ํ•ด๋‹นํ•˜๋Š” ์ฝ”๋“œ/์ด๋ฉ”์ผ ์„ธํŠธ (VerifyCode)๋ฅผ ์ฐพ์•„์˜จ๋‹ค.

์ฐพ์•„์˜ค์ง€ ๋ชปํ–ˆ์œผ๋ฉด false๋ฅผ ๋ฆฌํ„ดํ•œ๋‹ค.

์ž…๋ ฅ๋œ ์ฝ”๋“œ์™€ ์ฐพ์€ ์ฝ”๋“œ๊ฐ€ ๊ฐ™์œผ๋ฉด true๋ฅผ ๋ฆฌํ„ดํ•œ๋‹ค.

๋‘˜๋‹ค ์•„๋‹ˆ๋ฉด false๋ฅผ ๋ฆฌํ„ดํ•œ๋‹ค.

 

11. ํ…Œ์ŠคํŠธ

์ž˜๋ชป๋œ๊ฑฐ ์ž…๋ ฅํ•˜๋ฉด ์ธ์ฆ ์•ˆ๋˜๊ณ , ํ•œ๋ฒˆ ๋” sendํ•ด๋„ ์ธ์ฆ ์•ˆ๋œ๋‹ค.(์ง€์›Œ๋ฒ„๋ ค์„œ) ๋!