iOS小技能:短信验证码的Checklist、格式校验、获取验证码处理流程(限制60s)

6,288 阅读2分钟

本文正在参加「金石计划」

前言

短信验证码处理的实际应用:注册登陆界面获取验证码功能

  1. 获取验证码(限制60s):获取成功之后验证码输入框得到焦点,并开始计时器
  2. 格式校验
  3. 短信验证码的Checklist

I、实际应用的例子: 获取验证码(限制60s)

1.1 点击获取验证码处理

请求接口获取验证码,获取成功之后,开始到60S倒计时

  • 监听点击事件,并处理获取成功之后的倒计时
        UITapGestureRecognizer *cutTap = [[UITapGestureRecognizer alloc] init];
        [[cutTap rac_gestureSignal] subscribeNext:^(id x) {
            
            
            NSLog(@"获取验证码");
            
            
            if(weakSelf.model.rightBtnblock){
                
                // 参数为block
                
                
                weakSelf.model.rightBtnblock(
                                              
                                              
                                              ^(id  _Nonnull sender) {
                                
                //                                  []
                                                  [self.textF becomeFirstResponder];
                                                  [self startCountdown];//test code

                                                  
                            }// 参数
                                           );
                
            }
            
            
            
            
            
        }];
        [tmpView addGestureRecognizer:cutTap];
        

  • 请求短信验证码:SendValidateCode

 
/** 本方法的参数类型时block,是获取完短信验证码的回调
 ,回调主要是执行60S倒计时
 
 */
- (void)SendValidateCode:(void (^)(id sender))tmp {

        [QCTNetworkHelper Post:post parameters:params success:^(id  _Nonnull responseObj) {
            
            
            if(tmp){// 开始计时器
                tmp(nil);
            }
//
            
            
            
        } failure:nil bizFailure:nil isShowLoadingDataGif:YES];
        

1.2、计时方法处理

  • 去掉输入框的内容,短信验证码获取成功调用这个方法


#pragma mark - 计时方法, 去掉输入框的内容,短信验证码获取成功调用这个方法
//开始倒计时
- (void)startCountdown {
//
//    //1\ 清空文本输入框
    [self updateText:nil]; //
//
    _textF.userInteractionEnabled = YES;
    
    self.countdownTime = 60;
    
    self.rightBtn.enabled = NO;
    
    
    [self.rightBtn setTitle:[NSString stringWithFormat:@"%dS",self.countdownTime] forState:UIControlStateDisabled];
    if (_timer) {
        [_timer invalidate];
        _timer = nil;
    }
    [[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
}


//
//结束倒计时
- (void)stopCountdown {
    if (_timer) {
        [_timer invalidate];
        _timer = nil;
    }
    [self.rightBtn setTitle:@"重新发送" forState:UIControlStateNormal];
//    //    self.renewBtn.userInteractionEnabled = YES;
    self.rightBtn.enabled = YES;
    
    self.rightBtn.layer.borderColor = RGB(255,83,85).CGColor;
    [self.rightBtn setTitleColor:RGB(255,83,85) forState:UIControlStateNormal];
    
}



//
- (void)countdownAction:(NSTimer *)timer {
    self.countdownTime --;
    if (self.countdownTime < 0) {
        self.countdownTime = 0;
        [self stopCountdown];
    } else {
        [self.rightBtn setTitle:[NSString stringWithFormat:@"%dS",self.countdownTime] forState:UIControlStateDisabled];
    }
}
//
//
//
//
//
- (NSTimer *)timer {
    if (_timer == nil) {
        _timer = [NSTimer timerWithTimeInterval:1 target:self selector:@selector(countdownAction:) userInfo:nil repeats:YES];
    }
    return _timer;
}


II 格式正则校验

2.1 短信验证码格式正则校验

+ (BOOL)isSMSshouldChangeCharactersInRange:(NSString*)str{
    //匹配以0开头的数字
    
    //^\d{6}$"
    
//    NSPredicate * predicate0 = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",@"^[0][0-9]+$"];
    
    
    //
    NSPredicate * predicate1 = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",@"^[0-9]{0,6}$"];
    
    
    
    
    return  [predicate1 evaluateWithObject:str] ? YES : NO;
    
    
}


2.2 金额校验格式正则校验

需求背景:商户进件新增、编辑、变更;费率设置支持到小数点后3位,如微信支付宝费率0.385;d0费率0.015

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string{
    NSInteger len = range.length > 0?([textField.text length] - range.length): ([textField.text length] + [string length]);
    
    if(len > 20){// 限制20位
        return false;
    }
    
    NSMutableString * futureString = [NSMutableString stringWithString:textField.text];
    if(range.length > 0){//允许删除
        [futureString replaceCharactersInRange:range withString:string];
    }else if(range.length<=0){
        [futureString  insertString:string atIndex:range.location];
    }
    if(futureString.length<1){//允许删除全部
        return YES;
    }
    if(jjkFdTextF == textField){// 支持2位小数
        return [QCT_Common isAmoutshouldChangeCharactersInRange:futureString.copy ];
    }
    //支持三位小数
    return [QCT_Common isAmoutshouldChangeCharactersInRange3:futureString.copy];
    
}

支持三位小数

/**
 前端商户费率填写支持三位小数
 */
+ (BOOL)isAmoutshouldChangeCharactersInRange3:(NSString*)str{
    //匹配以0开头的数字
    NSPredicate * predicate0 = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",@"^[0][0-9]+$"];
    //匹配两位小数、整数
    NSPredicate * predicate1 = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",@"^(([1-9]{1}[0-9]*|[0])\.?[0-9]{0,3})$"];
    return ![predicate0 evaluateWithObject:str] && [predicate1 evaluateWithObject:str] ? YES : NO;
    
}

III、短信验证码的Checklist

  • 一次一用
  • 发送频率控制(建议60s获取一次)
  • 验证码有效期(建议60s内有效,发短信时进行友好提示)
  • 杂度(短信验证码建议6位数字)
  • 安全提示:是否是个人自己操作等风险提示信息
  • 在前端校验(客户端的校验只能作为辅助手段,很容易被绕过),必须使用服务端代码对输入数据进行最终校验
  • 短信验证码需要限制频率使用

例如:每天一个手机号码只允许发送5次,防止被黑客恶意消耗短信

  • 不同场景的短信验证码不可通用
  • 单个短信验证码限制有效验证次数
  • 验证码需要对应手机号不可通用