All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.taotao.boot.sms.common.service.impl.DefaultVerificationCodeService Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2020-2030, Shuigedeng ([email protected] & https://blog.taotaocloud.top/).
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.taotao.boot.sms.common.service.impl;

import com.taotao.boot.common.utils.lang.StringUtils;
import com.taotao.boot.sms.common.exception.PhoneIsNullException;
import com.taotao.boot.sms.common.exception.RetryTimeShortException;
import com.taotao.boot.sms.common.exception.TypeIsNullException;
import com.taotao.boot.sms.common.model.NoticeData;
import com.taotao.boot.sms.common.model.VerificationCode;
import com.taotao.boot.sms.common.model.VerificationCodeTypeGenerate;
import com.taotao.boot.sms.common.properties.VerificationCodeProperties;
import com.taotao.boot.sms.common.repository.VerificationCodeRepository;
import com.taotao.boot.sms.common.service.CodeGenerate;
import com.taotao.boot.sms.common.service.NoticeService;
import com.taotao.boot.sms.common.service.VerificationCodeService;
import com.taotao.boot.sms.common.utils.RandomUtils;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * 手机验证码服务实现
 *
 * @author shuigedeng
 * @version 2022.04
 * @since 2022-04-27 17:49:44
 */
@Service
public class DefaultVerificationCodeService implements VerificationCodeService {

    private final VerificationCodeRepository repository;

    private final VerificationCodeProperties config;

    private final NoticeService noticeService;

    private final CodeGenerate codeGenerate;

    private final VerificationCodeTypeGenerate verificationCodeTypeGenerate;

    public DefaultVerificationCodeService(
            VerificationCodeRepository repository,
            VerificationCodeProperties config,
            NoticeService noticeService,
            CodeGenerate codeGenerate,
            @Nullable VerificationCodeTypeGenerate verificationCodeTypeGenerate) {
        this.repository = repository;
        this.config = config;
        this.noticeService = noticeService;
        this.codeGenerate = codeGenerate;
        this.verificationCodeTypeGenerate = verificationCodeTypeGenerate;
    }

    @Override
    public String find(String phone, String identificationCode) {
        if (StringUtils.isBlank(phone)) {
            return null;
        }

        phoneValidation(phone);

        VerificationCode verificationCode = repository.findOne(phone, identificationCode);

        return verificationCode == null ? null : verificationCode.getCode();
    }

    @Nullable
    private String createIdentificationCode() {
        if (!config.isUseIdentificationCode()) {
            return null;
        }

        return RandomUtils.nextString(config.getIdentificationCodeLength());
    }

    @Override
    public void send(String tempPhone, @Nullable String type) {
        String phone = StringUtils.trimToNull(tempPhone);

        if (phone == null) {
            throw new PhoneIsNullException();
        }

        phoneValidation(phone);

        String identificationCode = createIdentificationCode();
        VerificationCodeCheckResult verificationCodeCheckResult = verificationCodeCheck(phone, identificationCode);
        VerificationCode verificationCode = verificationCodeCheckResult.verificationCode;

        Map params = buildSendParams(verificationCode);

        if (type == null && verificationCodeTypeGenerate != null) {
            type = verificationCodeTypeGenerate.getType(phone, params);
        }
        if (type == null) {
            type = config.getType();
        }
        if (type == null) {
            throw new TypeIsNullException();
        }

        NoticeData notice = new NoticeData();
        notice.setType(type);
        notice.setParams(params);

        if (noticeService.send(notice, phone) && verificationCodeCheckResult.newVerificationCode) {
            repository.save(verificationCode);
        }
    }

    private VerificationCodeCheckResult verificationCodeCheck(String phone, @Nullable String identificationCode) {
        VerificationCode verificationCode = repository.findOne(phone, identificationCode);
        Long expirationTime = config.getExpirationTime();

        boolean newVerificationCode = false;
        if (verificationCode == null) {
            verificationCode = new VerificationCode();
            verificationCode.setPhone(phone);
            verificationCode.setIdentificationCode(identificationCode);

            Long retryIntervalTime = config.getRetryIntervalTime();

            if (expirationTime != null && expirationTime > 0) {
                verificationCode.setExpirationTime(LocalDateTime.now().plusSeconds(expirationTime));
            }
            if (retryIntervalTime != null && retryIntervalTime > 0) {
                verificationCode.setRetryTime(LocalDateTime.now().plusSeconds(retryIntervalTime));
            }

            verificationCode.setCode(codeGenerate.generate());
            newVerificationCode = true;
        } else {
            LocalDateTime retryTime = verificationCode.getRetryTime();

            if (retryTime != null) {
                long surplus = Duration.between(LocalDateTime.now(), retryTime).getSeconds();
                if (surplus > 0) {
                    throw new RetryTimeShortException(surplus);
                }
            }
        }

        VerificationCodeCheckResult result = new VerificationCodeCheckResult();
        result.verificationCode = verificationCode;
        result.newVerificationCode = newVerificationCode;

        return result;
    }

    private Map buildSendParams(VerificationCode verificationCode) {
        Long expirationTime = config.getExpirationTime();
        Map params = new HashMap<>(4);
        params.put(MSG_KEY_CODE, verificationCode.getCode());
        if (verificationCode.getIdentificationCode() != null) {
            params.put(MSG_KEY_IDENTIFICATION_CODE, verificationCode.getIdentificationCode());
        }
        if (config.isTemplateHasExpirationTime() && expirationTime != null && expirationTime > 0) {
            params.put(MSG_KEY_EXPIRATION_TIME_OF_SECONDS, String.valueOf(expirationTime));
            params.put(MSG_KEY_EXPIRATION_TIME_OF_MINUTES, String.valueOf(expirationTime / 60));
        }
        return params;
    }

    private static class VerificationCodeCheckResult {

        VerificationCode verificationCode;

        boolean newVerificationCode;
    }

    @Override
    public boolean verify(String phone, String code, @Nullable String identificationCode) {
        if (StringUtils.isAnyBlank(phone, code)) {
            return false;
        }

        phoneValidation(phone);

        VerificationCode verificationCode = repository.findOne(phone, identificationCode);

        if (verificationCode == null) {
            return false;
        }

        boolean verifyData = Objects.equals(verificationCode.getCode(), code);

        if (verifyData && config.isDeleteByVerifySucceed()) {
            repository.delete(phone, identificationCode);
        }

        if (!verifyData && config.isDeleteByVerifyFail()) {
            repository.delete(phone, identificationCode);
        }

        return verifyData;
    }

    private void phoneValidation(String phone) {
        if (!noticeService.phoneRegValidation(phone)) {
            throw new PhoneIsNullException();
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy