手机验证码登录 代码实现 前端和后端

在这里插入图片描述
需求: 手机验证码登录,点击发送验证码,输入验证码,登录;
思路:

  1. 输入手机号,点击发送验证码按钮,单击事件触发 前端页面校验手机号格式是否正确,如不正确就返回手机号有误,正确就携带手机号发送请求,在发送请求前做一个倒计时效果;
  2. 后台接收到手机号,生成验证码,并将验证码保存在redis中手机号为key,验证码为value设置一个过期时间,调用发送短信服务传入手机号和验证码;
  3. 用户接收到验证码,输入验证码,前端同样进行一个校验,校验通过传入后端;
  4. 后端拿到数据,根据手机号查询验证码,返回结果;

注意事项: 避免出现恶意多次发送验证码,可以对手机号发送的验证码数量进行限制,3小时内最多发送3次验证码;

前端页面:
导入相关的工具js

//获取指定的URL参数值 如:http://localhost/pages/setmeal_detail.html?id=3&name=jack
function getUrlParam(paraName) {
    var url = document.location.toString();
    //alert(url);
    //从?开始剪切
    var arrObj = url.split("?");
    //如果有值表示有参数
    if (arrObj.length > 1) {
    //去掉?号以&分隔符在剪切
        var arrPara = arrObj[1].split("&");
        var arr;
        //遍历,拿到在键值对,以=号剪切,得到参数值
        for (var i = 0; i < arrPara.length; i++) {
            arr = arrPara[i].split("=");
            if (arr != null && arr[0] == paraName) {
                return arr[1];
            }
        }
        return "";
    }
    else {
        return "";
    }
}

//获得当前日期,返回字符串
function getToday() {
    var today = new Date();
    var year = today.getFullYear();
    var month = today.getMonth() + 1;//0表示1月,1表示2月
    var day = today.getDate();
    return (year + "-" + month + "-" + day);
}

//获得指定日期后指定天数的日期
function getSpecifiedDate(date,days) {
    date.setDate(date.getDate() + days);//获取指定天之后的日期
    var year = date.getFullYear();
    var month = date.getMonth() + 1;
    var day = date.getDate();
    return (year + "-" + month + "-" + day);
}

/**
 * 手机号校验
 1--以1为开头;
 2--第二位可为3,4,5,7,8,中的任意一位;
 3--最后以0-9的9个整数结尾。
 */
function checkTelephone(telephone) {
    var reg=/^[1][3,4,5,7,8][0-9]{9}$/;
    if (!reg.test(telephone)) {
        return false;
    } else {
        return true;
    }
}

/**
 * 身份证号码校验
 * 身份证号码为15位或者18位,15位时全为数字,18位前17位为数字,最后一位是校验位,可能为数字或字符X
 */
function checkIdCard(idCard){
    var reg = /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/;
    if(reg.test(idCard)){
        return true;
    }else{
        return false;
    }
}

var clock = '';//定时器对象,用于页面30秒倒计时效果
var nums = 30;
var validateCodeButton;//按钮对象
//基于定时器实现30秒倒计时效果
function doLoop() {
    validateCodeButton.disabled = true;//将按钮置为不可点击
    nums--;
    if (nums > 0) {
        validateCodeButton.value = nums + '秒后重新获取';
    } else {
        clearInterval(clock); //清除js定时器
        validateCodeButton.disabled = false;//按钮又可以点击了
        validateCodeButton.value = '重新获取验证码';
        nums = 30; //重置时间
    }
}

以下才是登录页面

<!DOCTYPE html>
<html lang="zh-CN">
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
        <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0,user-scalable=no,minimal-ui">
        <meta name="description" content="">
        <meta name="author" content="">
        <link rel="icon" href="../img/asset-favico.ico">
        <title>登录</title>
        <link rel="stylesheet" href="../css/page-health-login.css" />
        <link rel="stylesheet" href="../plugins/elementui/index.css" />
        <script src="../plugins/jquery/dist/jquery.min.js"></script>
        <script src="../plugins/healthmobile.js"></script>
        <script src="../plugins/vue/vue.js"></script>
        <script src="../plugins/vue/axios-0.18.0.js"></script>
        <script src="../plugins/elementui/index.js"></script>
    </head>
    <body data-spy="scroll" data-target="#myNavbar" data-offset="150">
    <div class="app" id="app">
        <!-- 页面头部 -->
        <div class="top-header">
            <span class="f-left"><i class="icon-back"></i></span>
            <span class="center">健康生活</span>
            <span class="f-right"><i class="icon-more"></i></span>
        </div>
        <div style="margin-left: 20px">手机快速登录</div>
        <!-- 页面内容 -->
        <div class="contentBox">
            <div class="login">
                <form id='login-form'>
                    <div class="input-row">
                        <label>手机号</label>
                        <div class="loginInput">
                            <input v-model="loginInfo.telephone" id='account' type="text" placeholder="请输入手机号">
                            <input id="validateCodeButton" @click="sendValidateCode()" type="button" style="font-size: 12px" value="获取验证码">
                        </div>
                    </div>
                    <div class="input-row">
                        <label>验证码</label>
                        <div class="loginInput">
                            <input v-model="loginInfo.validateCode" style="width:80%" id='password' type="text" placeholder="请输入验证码">
                        </div>
                    </div>
                    <div class="input-row" style="font-size: 12px">
                        <input type="checkbox" checked>
                        阅读并同意《健康生活用户协议》《健康生活隐私条款》
                    </div>
                    <div class="btn yes-btn"><a @click="login()" href="#">登录</a></div>
                </form>
            </div>
        </div>
    </div>
    </body>
    <script>
        var vue = new Vue({
            el:'#app',
            data:{
                loginInfo:{}//登录信息
               },
            methods:{
                //发送验证码
                sendValidateCode(){
                    //获取用户输入的手机号
                    var telephone = this.loginInfo.telephone;
                    //调用js方法,校验输入的手机号是否合法
                    if(!checkTelephone(telephone)){
                        //校验不通过,提示错误信息
                        this.$message.error("请输入正确的手机号");
                        return false;
                    }
                    //在按钮上显示30秒倒计时效果
                    validateCodeButton = $("#validateCodeButton")[0];//锁定dom对象
                    clock = window.setInterval(doLoop,1000);//定时器方法,可以实现每隔指定的时间调用指定的方法
                    //发送ajax请求,为用户发送手机验证码
                    axios.post("/validateCode/send4Login.do?telephone=" + telephone).then((res) => {
                        if(!res.data.flag){
                            //短信验证码发送失败
                            this.$message.error(res.data.message);
                        }
                    });
                },
                //登录
                login(){
                //为了防止在输入验证码后手机号更换了或者删除了,发送无效请求,所以这里还要再对手机号进行校验
                    //获取用户输入的手机号
                    var telephone = this.loginInfo.telephone;
                    //调用js方法,校验输入的手机号是否合法
                    if(!checkTelephone(telephone)){
                        //校验不通过,提示错误信息
                        this.$message.error("请输入正确的手机号");
                        return false;
                    }
                    //发送ajax请求,将表单数据提交到Controller进行登录处理
                    axios.post("/member/login.do",this.loginInfo).then((res) => {
                        if(res.data.flag){
                            //登录成功,跳转到会员首页
                            window.location.href = "member.html";
                        }else{
                            this.$message.error(res.data.message);
                        }
                    });
                }
            }
        });
    </script>
</html>

后端 发送短信服务详情见https://editor.csdn.net/md/?articleId=105281059
发送验证码

/**
 * 验证码操作
 */

@RestController
@RequestMapping("/validateCode")
public class ValidateCodeController {
    @Autowired
    private JedisPool jedisPool;

    //用户在线预约发送验证码
    @RequestMapping("/send4Order")
    public Result send4Order(String telephone){
        //首先调用方法随机生成4位数字验证码
        Integer validateCode = ValidateCodeUtils.generateValidateCode(4);
        //给用户发送验证码
        try{
        //发送短信可能会出现异常,使用try  catch
            SMSUtils.sendShortMessage(SMSUtils.VALIDATE_CODE,telephone,validateCode.toString());
        }catch (Exception e){
            e.printStackTrace();
            return new Result(false, MessageConstant.SEND_VALIDATECODE_FAIL);
        }
        //将验证码保存到redis(有效期5分钟)
        jedisPool.getResource().setex(telephone + RedisMessageConstant.SENDTYPE_ORDER,300,validateCode.toString());
        return new Result(true,MessageConstant.SEND_VALIDATECODE_SUCCESS);
    }

    //用户手机快速登录发送验证码
    @RequestMapping("/send4Login")
    public Result send4Login(String telephone){
        //随机生成6位数字验证码
        Integer validateCode = ValidateCodeUtils.generateValidateCode(6);
        //给用户发送验证码
        try{
            SMSUtils.sendShortMessage(SMSUtils.VALIDATE_CODE,telephone,validateCode.toString());
        }catch (Exception e){
            e.printStackTrace();
            return new Result(false, MessageConstant.SEND_VALIDATECODE_FAIL);
        }
        //将验证码保存到redis(5分钟)
        jedisPool.getResource().setex(telephone + RedisMessageConstant.SENDTYPE_LOGIN,300,validateCode.toString());
        return new Result(true,MessageConstant.SEND_VALIDATECODE_SUCCESS);
    }
}


手机号码登录


@RestController
@RequestMapping("/member")
public class MemberController {
    @Autowired
    private JedisPool jedisPool;

    @Reference
    private MemberService memberService;

    //手机号快速登录
    @RequestMapping("/login")
    public Result login(HttpServletResponse response, @RequestBody Map map){
    
        String telephone = (String) map.get("telephone");//获取手机号码
        String validateCode = (String) map.get("validateCode");//获取验证码
        //从Redis中获取保存的验证码
        String validateCodeInRedis = jedisPool.getResource().get(telephone + RedisMessageConstant.SENDTYPE_LOGIN);
           //验证码输入正确
        if(validateCodeInRedis != null && validateCode != null && validateCode.equals(validateCodeInRedis)){
         
            //判断当前用户是否为会员(查询会员表来确定)
            Member member = memberService.findByTelephone(telephone);
            if(member == null){
                //不是会员,自动完成注册(自动将当前用户信息保存到会员表)
                member.setRegTime(new Date());
                member.setPhoneNumber(telephone);
                memberService.add(member);
            }
            //向客户端浏览器写入Cookie,内容为手机号
            Cookie cookie = new Cookie("login_member_telephone",telephone);
            cookie.setPath("/");
            cookie.setMaxAge(60*60*24*30);
            response.addCookie(cookie);
            //将会员信息保存到Redis
            String json = JSON.toJSON(member).toString();
            jedisPool.getResource().setex(telephone,60*30,json);
            return new Result(true,MessageConstant.LOGIN_SUCCESS);
        }else{
            //验证码输入错误
            return new Result(false, MessageConstant.VALIDATECODE_ERROR);

        }
    }
}

  • 15
    点赞
  • 98
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值