IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 开发测试 -> 用户注册短信验证码(防刷) -> 正文阅读

[开发测试]用户注册短信验证码(防刷)

用户注册短信验证码防刷

1.使用场景

  • 注册验证
  • 信息变更: 修改密码、手机号等个人信息时,确保是用户本人操作,进行短信验证
  • 找回密码
  • 动态登录

2.防刷目的

  • 防止被黑客利用进行短信轰炸,防止浪费短信余额

3.防刷手段

  • 前端图形验证码
  • 前端滑动类
  • 前端点击类
  • 单个手机号请求限制
  • 单个ip请求限制
  • 手机号码真实性限制

4.实战操作

下面介绍一下图形验证码方式

  1. 引入依赖
            <dependency>
                <groupId>cn.hutool</groupId>
                <artifactId>hutool-all</artifactId>
                <version>5.7.16</version>
            </dependency>
  1. 短信配置

    这里使用的是阿里云的短信服务

    链接:https://market.aliyun.com/products/57000002/cmapi00046920.html?spm=5176.2020520132.101.1.14247218o2uxXD#sku=yuncode4092000001

    #配置短信服务
    sms:
      #添加aliyun上的appCode
      app-code: xxxxxxxxxxxxxxxxx
      template-id: M72CB42894
    
    // 配置类
    @ConfigurationProperties("sms")
    @Component
    @Data
    public class SmsConfig {
        private String appCode;
        private String templateId;
    }
    
    // 短信发送组件
    @Component
    @Slf4j
    public class SmsComponent {
        /**
         * 发送地址
         */
        private static final String URL_TEMPLATE = "https://jmsms.market.alicloudapi.com/sms/send?mobile=%s&templateId=%s&value=%s";
    
        @Autowired
        private RestTemplate restTemplate;
    
        @Autowired
        private SmsConfig smsConfig;
    
        /**
         * @param to         手机号
         * @param templateId 短信模板id
         * @param value      验证码
         */
        public void send(String to, String templateId, String value) {
            String url = String.format(URL_TEMPLATE, to, templateId, value);
    
            HttpHeaders headers = new HttpHeaders();
            //最后在header中的格式(中间是英文空格)为Authorization:APPCODE 83359fd73fe94948385f570e3c139105
            headers.set(HttpHeaders.AUTHORIZATION, "APPCODE " + smsConfig.getAppCode());
    
            HttpEntity<String> entity = new HttpEntity<>(headers);
            ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, entity, String.class);
    
            log.info("url={},body={}", url, response.getBody());
            if (response.getStatusCode() == HttpStatus.OK) {
                log.info("发送短信成功,响应信息:{}", response.getBody());
            } else {
                log.error("发送短信失败,响应信息:{}", response.getBody());
            }
        }
    }
    
    // 发送短信验证码请求对象
    @Data
    public class SendCodeRequest {
        /**
         * 图形验证码
         */
        private String captcha;
    
        /**
         * 登录的手机号/邮箱
         */
        private String to;
    }
    
    // 验证码类型
    public enum SendCodeEnum {
        // 用于注册
        USER_REGISTER;
    }
    
  2. 图形验证码接口

        @Autowired
        private StringRedisTemplate redisTemplate;
    
        /**
         * 图形验证码10分钟有效
         */
        private static final Duration CAPTCHA_CODE_EXPIRED = Duration.ofMinutes(10);
    
        /**
         * 获取图形验证码
         *
         * @return
         */
        @GetMapping("/captcha")
        public void getCaptcha(HttpServletRequest request, HttpServletResponse response) {
            // 利用hutool工具包,生成图形验证码对象
            LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(200, 100, 4, 150);
            try {
                // 验证码
                String code = lineCaptcha.getCode();
                // 存储到redis中
                redisTemplate.opsForValue().set(getCaptchaKey(request), code, CAPTCHA_CODE_EXPIRED);
                log.info("图形验证码code:{}", code);
                lineCaptcha.write(response.getOutputStream());
            } catch (IOException e) {
                log.error("图形验证码出错:{}", e.getMessage());
            }
        }
    
        /**
         * 生成/获取图形验证码缓存key
         *
         * @param request
         * @return
         */
        private String getCaptchaKey(HttpServletRequest request) {
            // 根据request获取到ip
            String ip = CommonUtil.getIpAddr(request);
            String userAgent = request.getHeader(HttpHeaders.USER_AGENT);
            String key = "zhuyz:captcha:" + CommonUtil.MD5(ip + userAgent);
            return key;
        }
    
  3. 短信验证码接口

        @Autowired
        private StringRedisTemplate redisTemplate;
    
    /**
         * 发送短信验证码
         *
         * @param sendCodeRequest
         * @param request
         * @return
         */
        @PostMapping("/send_code")
        public JsonData sendCode(@RequestBody SendCodeRequest sendCodeRequest, HttpServletRequest request) {
            // 1.校验图形验证码
            String captchaKey = getCaptchaKey(request);
            String captchaCacheValue = redisTemplate.opsForValue().get(captchaKey);
            if (ObjectUtil.isNull(captchaCacheValue)
                    && ObjectUtil.isNull(sendCodeRequest.getCaptcha())
                    && !StrUtil.equalsIgnoreCase(captchaCacheValue, sendCodeRequest.getCaptcha())) {
                return JsonData.buildResult(BizCodeEnum.CODE_CAPTCHA_ERROR);
            }
            // 2.删除图形验证码key&发送短信
            redisTemplate.delete(captchaKey);
            return notifyService.sendCode(SendCodeEnum.USER_REGISTER, sendCodeRequest.getTo());
        }
    
     /**
         * 短信验证码10分钟有效期
         */
        public static final Duration CODE_EXPIRED = Duration.ofMinutes(10);
    
        @Autowired
        private StringRedisTemplate redisTemplate;
    
        @Autowired
        private SmsComponent smsComponent;
    
        @Autowired
        private SmsConfig smsConfig;
    
        /**
         * 1.判断redis是否存在对应的短信验证码
         *      存在并且时间差小于60s,则为重复发送
         *      反之则生成短信验证码,缓存并且发送短信
         *
         * @param sendCodeEnum
         * @param to
         * @return
         */
        @Override
        public JsonData sendCode(SendCodeEnum sendCodeEnum, String to) {
            // 1.判断是否重复发送短信
            String cacheCodeKey = String.format(RedisKey.CHECK_CODE_KEY, sendCodeEnum.name(), to);
            // 数据格式:smsCode_timestamp
            String cacheCodeValue = redisTemplate.opsForValue().get(cacheCodeKey);
            if (StrUtil.isNotBlank(cacheCodeValue)) {
                List<String> split = StrUtil.split(cacheCodeValue, "_");
                // 时间差
                long gap = System.currentTimeMillis() - Long.parseLong(split.get(1));
                if (gap < 60) {
                    // 重复发送
                    return JsonData.buildResult(BizCodeEnum.CODE_LIMITED);
                }
            }
    
            // 2.生成短信验证码,缓存并且发送短信
            String smsCode = RandomUtil.randomNumbers(6);
            // 新的缓存的值
            String value = StrUtil.join("_", smsCode, System.currentTimeMillis());
            redisTemplate.opsForValue().set(cacheCodeKey, value, CODE_EXPIRED);
    
            if (Validator.isEmail(to)) {
                // 发送邮件
    
            } else if (Validator.isMobile(to)) {
                // 发送短信
                smsComponent.send(to, smsConfig.getTemplateId(), smsCode);
            }
            return JsonData.buildSuccess();
        }
    
  开发测试 最新文章
pytest系列——allure之生成测试报告(Wind
某大厂软件测试岗一面笔试题+二面问答题面试
iperf 学习笔记
关于Python中使用selenium八大定位方法
【软件测试】为什么提升不了?8年测试总结再
软件测试复习
PHP笔记-Smarty模板引擎的使用
C++Test使用入门
【Java】单元测试
Net core 3.x 获取客户端地址
上一篇文章      下一篇文章      查看所有文章
加:2022-04-09 18:47:46  更:2022-04-09 18:48:38 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/18 0:42:47-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码