验证码是保护系统安全的重要防线,本文将完整解析前后端分离架构中验证码功能的实现原理与代码实践。

一、验证码的核心作用

  1. 防暴力破解:增加恶意登录的时间成本

  2. 阻断自动化脚本:防止机器人批量攻击

  3. 安全加固:作为密码之外的第二道安全屏障

二、后端实现(Spring Boot)

1. 验证码生成与存储
@RestController
public class CaptchaController {
    
    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @GetMapping("/captcha")
    public Result generateCaptcha() {
        // 创建数学公式验证码(可切换为图形验证码)
        CircleCaptcha captcha = CaptchaUtil.createCircleCaptcha(150, 40, 4, 4);
        
        String code = captcha.getCode().toUpperCase(); // 验证码文本
        String uuid = IdUtil.simpleUUID(); // 唯一标识
        
        // 存储到Redis(120秒有效期)
        redisTemplate.opsForValue().set(
            "captcha:" + uuid, 
            code,
            120, 
            TimeUnit.SECONDS
        );
        
        // 构造响应数据
        Map<String, Object> result = new HashMap<>();
        result.put("uuid", uuid);
        result.put("img", captcha.getImageBase64Data());
        
        return Result.ok().data(result);
    }
}

三、前端实现(Vue + ElementUI)

1. 验证码组件
//vue组件
<template>
  <el-form-item prop="code">
    <el-input v-model="loginForm.code" placeholder="验证码" />
    <div class="captcha-img">
      <img :src="'data:image/png;base64,' + captchaImg" @click="refreshCaptcha">
    </div>
  </el-form-item>
</template>

<script>
export default {
  data() {
    return {
      loginForm: {
        username: '',
        password: '',
        code: '',
        uuid: ''
      },
      captchaImg: ''
    }
  },
  methods: {
    // 获取验证码
    async refreshCaptcha() {
      const res = await getCaptchaImg();
      this.captchaImg = res.img;
      this.loginForm.uuid = res.uuid;
    },
    
    // 登录提交
    async handleLogin() {
      await this.$refs.form.validate();
      
      try {
        await login(this.loginForm);
        // 登录成功跳转...
      } catch (error) {
        // 失败时刷新验证码
        this.refreshCaptcha(); 
      }
    }
  },
  mounted() {
    this.refreshCaptcha();
  }
}
</script>

四、关键技术解析

  1. 验证码生成工具

    • Hutool的CircleCaptcha:创建带干扰线的数学公式验证码

    • 可切换为ShearCaptcha(扭曲图形验证码)或GifCaptcha(动态验证码)

  2. Redis存储设计

    • Key: "captcha:3b4e5c6d-7f8a-90b1-c2d3e4f5a6b7"
      Value: "A3F8" # 验证码文本
      TTL: 120秒   # 短时效保障安全

      2

  3. 安全增强策略

    • 验证码全大写比对:.equalsIgnoreCase()

    • 单次有效性:验证后立即删除Redis记录

    • 请求频率限制:IP级验证码获取限流

 

五、最佳实践建议

  1. 多类型验证码切换

    // 根据安全级别动态选择
    Captcha createCaptcha(int securityLevel) {
      switch(securityLevel) {
        case 1: return new LineCaptcha();
        case 2: return new CircleCaptcha();
        case 3: return new GifCaptcha();
        default: return new ShearCaptcha();
      }
    }

  2. 行为验证码集成

    • 滑块验证:使用AJ-Captcha等开源方案

    • 文字点选:结合机器学习识别复杂场景

  3. 监控与告警

    // 记录验证失败日志
    @Aspect
    public class CaptchaAspect {
      @AfterThrowing(pointcut = "execution(* login(..))", throwing = "ex")
      public void logFailedAttempt(Throwable ex) {
        if ("验证码错误".equals(ex.getMessage())) {
          securityLogService.logFailedAttempt();
        }
      }
    }

六、总结

验证码功能实现需关注三个核心维度:

  1. 生成复杂度 - 平衡用户体验与安全性

  2. 传输安全 - Base64编码直传避免额外请求

  3. 验证可靠性 - Redis保证验证状态的原子性

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐