본문 바로가기

개발

[Springboot + Redis + CoolSms] 회원가입 인증 부분 문제 해결

현재 로직

1. User가 회원가입 진행 시 coolSms를 통해 인증코드를 발급받는다.

2. redis에 sms:{email} 형식으로 저장되면 data에 발급받은 coolSms로 전송된 인증 코드를 저장한다.

3. User가 전송받은 인증코드를 [확인] 버튼을 누를 경우 redis 내의 코드와 비교한다. 

 

→ 현재는 보안을 생각해서 이 단계에서 인증 코드를 삭제하지 않고, 회원가입 버튼을 누를 경우 DTO에 인증 코드를 다시 전송하여 회원가입 로직에서 Redis의 인증 코드와 일치하는지 다시 확인한다.

인증 코드 검증과 회원가입 버튼을 누르기까지 큰 시간의 차이가 없어서 괜찮을 것 같지만 뭔가 찝찝한게 문제.......

 

 

오.!>!>1>!>!!>?!!?~ 귀찮 ㅠ

 

Redis 전화번호 인증 성공 시 

1. module-common → [SmsServiceImpl]

- 전화번호 인증 성공 시 redis에 verified_phone:{phone} 형식으로 저장, 타임아웃은 10분으로 지정

@Override
    public boolean verifySms(SmsVerifyRequest smsVerifyRequest){
        String phone = smsVerifyRequest.getPhoneNum();
        Sms sms =  findSmsByPhone(phone);
        if(sms.getCode().equals(smsVerifyRequest.getCertificationCode())){
            deleteByPhone(phone);
            verifyPhone(phone);
            return true;
        }
        return false;
    }


public void verifyPhone(String phone) {
        // Redis에 "verified_phone:{phone}" 형식으로 저장
        String redisKey = "verified_phone:" + phone;

        // 로그아웃 상태를 기록 (true로 설정)
        redisTemplate.opsForValue().set(redisKey, "verify");

        // 1시간 동안 유효 (예: 로그아웃 상태를 1시간 동안 유지)
        redisTemplate.expire(redisKey, Duration.ofMinutes(10));
    }

 

 

2. module-common → [AuthServiceImpl]

 - 회원가입 시 redis에 verified_phone:{phone} 있는지 확인하는 로직 추가

 - 확인 완료 시 redis 내 해당 인증정보 삭제

/** [일반] 이메일 회원가입 API
     * 이메일, 전화번호, 닉네임 중복 체크
     * 중복 없을 시 member 저장
     * 프로필 저장 Version
     * */
    @Transactional
    public void signup(SignupRequest request) {

        // CHECK EMAIL, PHONE, NICKNAME DUPLICATE
        if(memberService.existByEmail(request.getEmail())){
            throw new DataIntegrityViolationException("중복되는 이메일입니다.");
        }

        if(memberService.existByPhone(request.getPhone())){
            throw new DataIntegrityViolationException("중복되는 전화번호입니다.");
        }

        if(memberService.existByNickname(request.getNickname())){
            throw new DataIntegrityViolationException("중복되는 닉네임입니다.");
        }

        // 인증되지않은 전화번호
        if(!isTokenPhone(request.getPhone())){
            throw new DataIntegrityViolationException("잘못된 요청입니다.");
        }

        // 회원가입 후 Redis에 저장된 전화번호 인증 정보를 삭제
        deletePhoneNumberVerification(request.getPhone());

        Member member = Member.builder()
                .email(request.getEmail())
                .nickname(request.getNickname())
                .phone(request.getPhone())
                .gender(request.getGender())
                .password(passwordEncoder.encode(request.getPassword()))
                .birthday(request.getBirthday())
                .role(Role.ROLE_USER)
                .provider(Provider.NORMAL)
                .build();

        // SAVE MEMBER ENTITY
        memberService.saveMember(member);
    }

 

 /**
     * redis에 인증된 전화번호인지 체크
     * */
    public boolean isTokenPhone(String phone) {
        // Redis에 해당 번호가 존재하는지 확인
        return Boolean.TRUE.equals(redisTemplate.hasKey(getRedisKeyForToken(phone)));
    }
    private String getRedisKeyForToken(String token) {
        return "verified_phone:" + token;
    }

 


테스트

 

  • 전화번호 인증없이 바로 회원가입 API에 데이터를 넣은 경우 → 실패

인증없이 추가한 경우 예외처리 됨 (아직 예외처리 코드를 지정하지않아서 이후에 변경 예정)

 

 

  • 인증번호 발급

 

 

  • 인증 완료

 

 

  • Redis 내에 인증된 전화번호로 등록 성공

 

 

  • 회원가입 → 실패

Redis 내에서도 해당 전화번호 인증 정보가 정상적으로 삭제되었다