Build a Secure SMS Verification Service with Spring Boot and Redis

This tutorial walks through creating a simulated SMS verification system using Spring Boot, Redis, and scheduled tasks, covering requirements, dependency setup, controller and service implementation, rate limiting, code expiration, validation logic, and daily reset of usage counters.

Java Architect Essentials
Java Architect Essentials
Java Architect Essentials
Build a Secure SMS Verification Service with Spring Boot and Redis

Overview

The article demonstrates how to simulate sending a 6‑digit SMS verification code to a mobile phone, store it in Redis, enforce daily request limits, handle expiration, and validate the code using Spring Boot.

Requirements

Send a phone number and return a random 6‑digit code.

Each phone can request a code up to 10 times per day (configurable to 3 for testing); the count resets at midnight.

If the daily limit is reached, return the message “当天验证码获取次数已达上限,请明天再次使用”.

Each code is valid for 5 minutes; the SMS text includes the code, validity period, and a usage‑limit notice.

If a request is made while a valid code still exists, return the remaining time, e.g., “已有可用验证码,XX分XX秒内依然有效”.

Validate the phone number and code, returning either “验证成功” or “验证失败,请确认手机号或验证码”.

Dependencies

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

Controller

@RestController
public class PhoneController {
    @Resource
    private PhoneService phoneService;

    @RequestMapping("/send")
    public String send(String phone) {
        return phoneService.send(phone);
    }

    @RequestMapping("/check")
    public String check(String phone, String code) {
        return phoneService.check(phone, code);
    }
}

Service Implementation

Key constants:

private static final int MAX_TIME_OUT = 5; // minutes
private static final String MAX_PHONE_COUNT = "3"; // daily limit for demo
private static final String PHONE_COUNT_SUFFIX = ":COUNT";
private static final String PHONE_CODE_SUFFIX = ":CODE";

Core logic (simplified):

public String send(String phone) {
    String countKey = phone + PHONE_COUNT_SUFFIX;
    String codeKey = phone + PHONE_CODE_SUFFIX;

    // limit check
    if (RedisStringUtil.get(codeKey) == null && "3".equals(RedisStringUtil.get(countKey))) {
        return "当天验证码获取次数已达上限,请明天再次使用";
    }

    // existing code still valid?
    long exTime = RedisKeyUtil.getExpire(codeKey);
    if (exTime > 0) {
        return "已有可用验证码," + (exTime / 60) + "分 " + (exTime % 60) + " 秒内依然有效";
    }

    // generate and store new code
    String code = getCode();
    RedisStringUtil.setEx(codeKey, code, MAX_TIME_OUT, TimeUnit.MINUTES);
    RedisStringUtil.incrBy(countKey, 1);
    return "【地笼系统】您的手机验证码为:" + code + ",有效期5分钟,此功能每天最多获取" + MAX_PHONE_COUNT + "条,请勿向任何人出示,以免账号被盗";
}

public String check(String phone, String code) {
    String codeKey = phone + PHONE_CODE_SUFFIX;
    if (code != null && code.equals(RedisStringUtil.get(codeKey))) {
        return "验证成功";
    }
    return "验证失败,请确认手机号或验证码";
}

private String getCode() {
    return String.valueOf(new Random().nextInt(900000) + 100000);
}

Scheduled Task for Daily Reset

@Configuration
public class TaskConfig {
    @Scheduled(cron = "0 0 0 * * ?") // runs at midnight
    public void clearPhoneCount() {
        RedisKeyUtil.delete(RedisKeyUtil.keys("*:COUNT"));
    }
}

Enable Scheduling

@EnableScheduling
@SpringBootApplication
public class RedisdemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(RedisdemoApplication.class, args);
    }
}

The complete source is available on the original CSDN blog (https://blog.csdn.net/weixin_37833693).

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

BackendJavaredisSchedulingSpring BootCode ExampleSMS Verification
Java Architect Essentials
Written by

Java Architect Essentials

Committed to sharing quality articles and tutorials to help Java programmers progress from junior to mid-level to senior architect. We curate high-quality learning resources, interview questions, videos, and projects from across the internet to help you systematically improve your Java architecture skills. Follow and reply '1024' to get Java programming resources. Learn together, grow together.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.