广告
返回顶部
首页 > 资讯 > 后端开发 > Python >Java实现短信验证码的示例代码
  • 131
分享到

Java实现短信验证码的示例代码

2024-04-02 19:04:59 131人浏览 独家记忆

Python 官方文档:入门教程 => 点击学习

摘要

目录项目需求需求来由代码实现发送验证码方法注册方法忘记密码前端代码编码中遇到的问题如何改进短信验证码相信大家都不陌生吗,但是短信验证码怎么生成的你真的了解吗,本文揭示本人项目中对短信

短信验证码相信大家都不陌生吗,但是短信验证码怎么生成的你真的了解吗,本文揭示本人项目中对短信验证码的。

项目需求

用户注册/忘记密码添加短信验证码

需求来由

登录注册页面需要确保用户同一个手机号只关联一个账号确保非人为操作,避免系统用户信息紊乱增加系统安全

代码实现

同事提供了WEBService接口,很好,之前没调过,又增加了困难。

这边用的阿里云的短信服务,废话少说上图,呸,上代码—

发送验证码方法

public ajaxResult sendVerificationCode(LoginBody loginBody) {
    //拼装Redis的key
    String redisCodeKey = Constants.RECRUIT_CODE_KEY + loginBody.getUserName();
    //通过判断过期时间检验是否发送过验证码如果发送直接return
    if (redisCache.getExpire(redisCodeKey) >= 0) {
        return AjaxResult.error(TipsConstants.YZM_SEND_ALREADY);
    }
    //生成随机6位验证码
    String redisCodeValue = VerifyCodeUtils.generateSmsCode();
    //验证码类型这是根据同事给的webservice的文档单独封装的目前先这么写了;判断其是注册还是忘记密码
    VerificationCodeType verificationCodeType = VerificationCodeType.getByCode(loginBody.getVerificationCodeType());
    String templateCode = null;
    switch (verificationCodeType) {
        case REGISTER:
            templateCode = VerificationCodeType.REGISTER.getCode();
            break;
        case FORGET_PASSWord:
            templateCode = VerificationCodeType.FORGET_PASSWORD.getCode();
            break;
        default:
            break;
    }
    //webservice接口需要JSON格式的参数
    jsONObject jsonObject = new JSONObject();
    jsonObject.put(WebServiceConstants.CODE, redisCodeValue);
    Map<String, String> resultMap = SMSUtils.sendMessage(loginBody.getUserName(),templateCode,jsonObject);
    //判断webservice接口返回的结果
    if (!resultMap.get(WebServiceConstants.SEND_SMS_RESULT).equals(Constants.SUCCESS)) {
        logger.info(resultMap.get(WebServiceConstants.OUT_MSG));
        logger.info(resultMap.get(WebServiceConstants.BIZ_ID));
        return AjaxResult.error(TipsConstants.MSG_SERVER_ERROR);
    }
    //存储到redis设置过期时间,这里设置了60s,根据需求来
    redisCache.setCacheObject(redisCodeKey, redisCodeValue, 60, TimeUnit.SECONDS);
    return AjaxResult.success();
}

注册方法

public AjaxResult register(LoginBody loginBody) {
    //拼装redis key
    String redisCodeKey = Constants.RECRUIT_CODE_KEY + loginBody.getUserName();
    //redisCache封装了redis的方法;
    //获取验证码判断验证码是否为空;输入的验证码与短信验证码是否一致
    String redisCodeValue = redisCache.getCacheObject(redisCodeKey);
    if (StringUtils.isEmpty(redisCodeValue) || !loginBody.getVerificationCode().equals(redisCodeValue)) {
        return AjaxResult.error(TipsConstants.YZM_ERROR);
    }
    //查表校验用户是否注册
    SysUser existUser = sysUserMapper.checkPhoneUnique(loginBody.getUserName());
    if (!ObjectUtil.isEmpty(existUser)) {
        return AjaxResult.error(TipsConstants.EXIST_USER_ERROR);
    }
    //对象copy,创建SysUser对象
    SysUser sysUser = BeanUtil.copyProperties(loginBody, SysUser.class, UserConstants.PASSWORD);
    sysUser.setPassword(SecurityUtils.encryptPassword(loginBody.getPassword()));
    //插入用户信息
    sysUserMapper.insertUser(sysUser);
    return AjaxResult.success(TipsConstants.REGISTER_SUCCESS);
}

忘记密码

public AjaxResult forgetPwd(LoginBody loginBody) {
    //拼装redis的key
    String redisCodeKey = Constants.RECRUIT_CODE_KEY + loginBody.getUserName();
    //获取验证码
    String redisCodeValue = redisCache.getCacheObject(redisCodeKey);
    if (!loginBody.getVerificationCode().equals(redisCodeValue)) {
        return AjaxResult.error(TipsConstants.YZM_ERROR);
    }
    //查表查询用户是否存在
    SysUser sysUser = sysUserMapper.checkPhoneUnique(loginBody.getUserName());
    if (ObjectUtil.isEmpty(sysUser)) {
        return AjaxResult.error(TipsConstants.NO_USER);
    }
    //密码加密
    loginBody.setPassword(SecurityUtils.encryptPassword(loginBody.getPassword()));
    //重置密码
    sysUserMapper.resetUserPwd(loginBody.getUserName(), loginBody.getPassword());
    return AjaxResult.success();
}

前端代码

这里只粘贴了发送验证码改变按钮的方法

sendCode(type) {
  this.$refs.registerFORM.validateField('phone',(phoneError)=> {
    if(!phoneError){
      this.registerForm.verificationCodeType = type
      //短信验证码最大请求次数校验
      getSmsCode(this.registerForm).then(response => {
        if (response.code !== 200) {
          this.requestMax = true
        } else {
          this.msgSuccess('发送成功,请注意查收短信')
          this.requestMax = false
        }
        //发送验证码按钮修改
        if (!this.requestMax) {
          let time = 60
          this.buttonText = '已发送'
          this.isDisabled = true
          if (this.flag) {
            this.flag = false
            let timer = setInterval(() => {
              time--
              this.buttonText = time + ' 秒'
              if (time === 0) {
                clearInterval(timer)
                this.buttonText = '重新获取'
                this.isDisabled = false
                this.flag = true
              }
            }, 1000)
          }
        }
      })
    }
  })
},

编码中遇到的问题

1.webservice如何调用?

一开始导了很多关于webservice的相关依赖,结果掉不通没办法只能用Hutool了,send返回的是一个xml,再用documet将其解析就ok了。

SoapClient soapClient = SoapClient.create(WebServiceConfig.getMsgUrl())
        .setMethod(WebServiceMethod.SendSms.getCode(), WebServiceConfig.getNamespaceUri())
        .setParams(map, false);
String result = soapClient.send()

2.不能让用户无限制的请求发送验证码

据说短信平台有验证逻辑,为了安全还是给系统封了一层;这里通过注解,aop配合redis计数器进行最大请求次数验证。

代码如下

注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CheckRequestTimes {
    
    String maxTimes() default "10";
    
    String maxSystermTimes() default "1000";
    
    RequestEnums reQtype() default RequestEnums.COMMON;
    
    String errorMsg() default TipsConstants.REQUEST_TIMES_MAX
}

Aspect

这部分代码我个人认为设计比较巧妙,可供读者思考,多利用设计模式思想去开发代码,让代码更优雅、更健壮、更可用,crud也有编出自己的骨气!!!(本实例涵盖了单例,模板方法)

@Aspect
@Component
@Order(2)
public class CheckRequestAspect {

    @Autowired
    RedisService redisService;
    @Autowired
    TokenService tokenService;

    private static Logger logger = LoggerFactory.getLogger(CheckRequestAspect.class);
    //防止并发,添加关键字实现共享
    private volatile ConcurrentHashMap<RequestEnums, RequestTimesAbstract> reqTimesProceSSMap;
    
    @PostConstruct
    public void initexcelProcessorFactory() {
        //dcl 双重检查,也可进行懒散加载。因为现在基于spring容器单例,此锁可适当调整
        if (MapUtil.isNotEmpty(reqTimesProcessMap)) {
            return;
        }
        //眼熟不这叫懒汉式单例
        synchronized (this) {
            if (ObjectUtil.isNull(reqTimesProcessMap)) {
                reqTimesProcessMap = new ConcurrentHashMap(8);
            }
            //这里其实可以采用工厂方法去改造,由于业务没有太多类型所以就不设计工厂了
            reqTimesProcessMap.put(RequestEnums.COMMON, new UserCommReqTimes());
            reqTimesProcessMap.put(RequestEnums.SMS, new SMSCodeReqTimes());
        }
    }
    
    @Pointcut("@annotation(com.fuwai.hr.common.annotation.CheckRequestTimes)")
    public void checkPoint() {

    }
    
    @Around("checkPoint()")
    public Object aroundMethod(ProceedingJoinPoint proceedingJoinPoint) {
        //获取方法上的注解
        CheckRequestTimes checkRequestTimes = getAnnotation(proceedingJoinPoint);
        Object[] args = proceedingJoinPoint.getArgs();
        //判断是否到达最大请求次数,这里为了应对不同请求类型的处理方式写了一个抽象类,
        //便于扩展维护,沿用了了模板方法设计模式的思想
        if(!reqTimesProcessMap.get(checkRequestTimes.reqType()).judgeMaxTimes(args, checkRequestTimes, redisService)){
            return AjaxResult.error(httpstatus.REQUEST_MAX, checkRequestTimes.errorMsg());
        }
        //执行请求方法
        Object proceed = null;
        try {
            proceed = proceedingJoinPoint.proceed();
        } catch (Throwable throwable) {
            logger.error(throwable.getMessage(), throwable);
        }
        return proceed;
    }
    
    private CheckRequestTimes getAnnotation(ProceedingJoinPoint proceedingJoinPoint) {
        MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();
        Method method = signature.getMethod();
        if (method != null){
            return method.getAnnotation(CheckRequestTimes.class);
        }
        return null;
    }
}

抽象模板类

public abstract class RequestTimesAbstract {
    
    public abstract boolean judgeMaxTimes(Object object, CheckRequestTimes checkRequestTimes, RedisService redisService);
}

短信模板子类

public class SMSCodeReqTimes extends RequestTimesAbstract {
    @Override
    public boolean judgeMaxTimes(Object object, CheckRequestTimes checkRequestTimes, RedisService redisService) {
        Object[] objects= (Object[])object;
        LoginBody loginBody = JSONObject.parseObject(JSONObject.toJSONString(objects[0]), LoginBody.class);
        String phone = Constants.RECRUIT_CODE_TIMES_KEY + loginBody.getUserName() + Constants.NUM;
        //本地只有一个服务器,拼接一个ip的key;如果是分布式这种方式就不太可取了根据需求来吧
        StringBuilder ip = new StringBuilder();
        ip.append(Constants.RECRUIT_CODE_TIMES_KEY).append(LocalHostUtil.getLocalIp()).append(Constants.DELIVERY).append(Constants.NUM);
        //判断本地系统的最大请求方式和用户的请求次数
        if (StringUtils.isNotEmpty(ip) && StringUtils.isNotEmpty(phone)) {
            return redisService.judgeMaxRequestTimes(ip.toString(), checkRequestTimes.maxSystermTimes()) && redisService.judgeMaxRequestTimes(phone, checkRequestTimes.maxTimes());
        }
        return false;
    }
}

RedisService判断请求方法

这里实现了一简单redis计数器自己随手写的也不知道对不对;rediscache封装的redis一些操作


@Override
public Boolean judgeMaxRequestTimes(String key, String max) {
    //获取key值,值为null插入值
    //不为null进行,判断是否到最大值,更新数值
    String value = redisCache.getCacheObject(key);
    if (StringUtils.isEmpty(value)) {
        //key存在的话不对齐进行操作,存在的话就他设置值
        redisCache.setIfAbsent(key, RecruitNumberConstants.NUMBER_1.toString(), RecruitNumberConstants.NUMBER_24, TimeUnit.HOURS);
        return true;
    }
    //最大次数 <= 当前访问次数
    if (Integer.valueOf(max).compareTo(Integer.valueOf(value)) <= RecruitNumberConstants.NUMBER_0) {
        return false;
    }
    //这里获取的是当前key的过期时间
    //(因为这边更新值的话,更新要不得设置过期时间要不不设置更新那ttl就变成了永久的了
    //两种方案都不合理那就只能获取他当前的剩余时间去更新了)
    Long expire = redisCache.getExpire(key);
    //key存在的话对其进行更新,不存在不对其进行操作
    return redisCache.setIfPresent(key, String.valueOf(Integer.parseInt(value) + RecruitNumberConstants.NUMBER_1), expire, TimeUnit.SECONDS);
}

如何改进

个人感觉这应该是不支持并发的,关于计数的操作可以用原子类去操作;我感觉我写的这玩意分布式估计也支持不了,有时间自己搭个环境再验证吧,懒得搞了。

到此这篇关于Java实现短信验证码的示例代码的文章就介绍到这了,更多相关Java 短信验证码内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: Java实现短信验证码的示例代码

本文链接: https://www.lsjlt.com/news/141812.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Java实现短信验证码的示例代码
    目录项目需求需求来由代码实现发送验证码方法注册方法忘记密码前端代码编码中遇到的问题如何改进短信验证码相信大家都不陌生吗,但是短信验证码怎么生成的你真的了解吗,本文揭示本人项目中对短信...
    99+
    2022-11-13
  • Redis实现短信验证码登录的示例代码
    目录效果图pom.xmlapplicatoin.ymlRedis配置类controllerserviceImplmapper效果图 发送验证码 输入手机号、密码以及验证码完成登录操作 pom.xml 核心依赖 <...
    99+
    2022-06-13
    Redis短信验证码登录 Redis验证码登录 Redis短信验证码
  • 短信验证码—Java实现
    在业务需求中我们经常会用到短信验证码,比如手机号登录、绑定手机号、忘记密码、敏感操作等,都可以通过短信验证码来保证操作的安全性,于是就记录下了一次开发的过程。 一.架构设计 发送短信是一个比较慢的过程,因为需要用到第三方服务(腾讯云短信...
    99+
    2023-08-17
    java rabbitmq redis 腾讯云 spring boot
  • SSM项目实现短信验证码登录功能的示例代码
    目录1.登入网站 zz短信平台2.导入工具类MessageUtil3.ajax 模块4. html页面5.编写controller层1.登入网站 zz短信平台 http:/...
    99+
    2022-11-13
  • Java如何实现短信验证码
    本篇内容主要讲解“Java如何实现短信验证码”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java如何实现短信验证码”吧!截图展示实现代码后台接收前台的kgCaptchaToken进行验证,验证...
    99+
    2023-07-05
  • Java实现滑动验证码的示例代码
    目录1.效果演示2.后端代码控制层工具类3.前端页面功能:java实现滑动验证码 项目是采用springboot,maven 开发工具:采用idea 1.效果演示 2.后端代码...
    99+
    2022-11-13
  • Android实现短信验证功能的代码
    在我们现在开发APP过程中,当用户注册时,短信验证是必不可少的操作,这里我们就是用一个免费的第三方短信验证SDK-MOP 首先看下效果图 获取AppKey和AppSecr...
    99+
    2022-06-06
    Android
  • vue_drf实现短信验证码
    目录一、需求1,需求二、sdk参数配置  1,目录结构三、代码实现1,后端代码2,前端代码一、需求 1,需求   我们在做网站开发时,登录页面很多情况下是可以用手机号接收短信验证码,...
    99+
    2022-11-12
  • Django使用celery异步发送短信验证码代码示例
    目录celery1.celery介绍1.1 celery应用举例1.2 Celery有以下优点1.3 Celery 特性2.工作原理2.1 Celery 扮演生产者和消费者的角色3....
    99+
    2022-11-12
  • vue实现通过手机号发送短信验证码登录的示例代码
    本文主要介绍了vue实现通过手机号发送短信验证码登录的示例代码,分享给大家,具体如下: <template> <div class="get-mobile...
    99+
    2022-11-13
  • javascript实现发送短信验证码案例
    本文实例为大家分享了javascript实现发送短信验证码的具体代码,供大家参考,具体内容如下 效果如下: 代码思路: 1.按钮点击之后,会禁用disabled 为true2.同时...
    99+
    2022-11-13
  • SpringBoot发送短信验证码的实例
    目录1、注册短信通账号2、导入依赖3、随机验证码的工具类4、短信发送工具类5、测试1、注册短信通账号 网址:http://sms.webchinese.cn 2、导入依赖 &...
    99+
    2022-11-13
  • java如何实现短信验证码功能
    要在Java中实现短信验证码功能,你可以按照以下步骤进行操作:1. 选择一个可靠的短信服务提供商:首先,你需要选择一个可靠的短信服务...
    99+
    2023-10-21
    java
  • 基于Redis实现短信验证码登录项目示例(附源码)
    目录Redis短信登录流程描述短信验证码的发送短信验证码的验证是否登录的验证源码分析模拟发送短信验证码短信验证码的验证校验是否登录登录验证优化Redis短信登录流程描述 短信验证码的...
    99+
    2022-11-13
  • Android实现发送短信验证码倒计时功能示例
    一、简介: 开发中在用户注册或找回密码之类的功能,经常会遇到获取短信验证码,获取验证码后需要等待1分钟倒计时,这段时间是不能再次发送短信请求的。 效果图: 二、实现步骤: ...
    99+
    2022-06-06
    发送短信 倒计时 示例 验证码 短信验证码 Android
  • Nodejs实现短信验证码功能
    使用Nodejs的开发者愈来越多,基于Nodejs的后台开发也多了起来,像短信验证码、短信群发、国际短信这些需求,完全可以采用第三方接口来实现,云片就提供了这样的接口。 Nodejs // 修改为您的a...
    99+
    2022-06-04
    验证码 短信 功能
  • vue怎么实现短信验证码
    这篇文章主要讲解了“vue怎么实现短信验证码”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“vue怎么实现短信验证码”吧!一、需求1,需求  我们在做网站开发...
    99+
    2022-10-19
  • Spring中使用腾讯云发送短信验证码的实现示例
    目录1.所需依赖2.腾讯云配置(1).获取短信签名(2).创建正文模板(3).创建密钥(4).获取SdkAppId3.代码1. 所需依赖 <dependency...
    99+
    2022-11-13
  • 阿里大于短信验证码node koa2的实现代码(最新)
    今天给大家分享一下最新版阿里大于的短信验证码在node koa2的实现,还是有很多坑需要注意。 首先需要在阿里云注册账号,并获取阿里云访问秘钥,在控制台完成模板与签名的申请获得调用接口的必备参数。具体方法参...
    99+
    2022-06-04
    阿里 验证码 代码
  • Java如何实现发送短信验证码功能
    小编给大家分享一下Java如何实现发送短信验证码功能,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!一个发送短信验证码的功能,使用的是信易通的短信平台接口,然后在J...
    99+
    2023-05-30
    java
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作