效果:60秒内校验手机验证码
步骤1:前端页面vue2+ElementU
<template>
<div>
<el-form :model="formInline" :rules="rules" ref="formInline" class="demo-form-inline" label-width="90px">
<el-form-item label="手机号" prop="authPhone">
<el-input v-model="formInline.authPhone" placeholder="请输入手机号" style="width: 360px"></el-input>
</el-form-item>
<el-form-item label="验证码" prop="authCode">
<el-input v-model="formInline.authCode" placeholder="请输入验证码" style="width: 180px"></el-input>
<el-button type="primary" @click="handleSend" :disabled="disable">{{ text }}</el-button>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm('formInline')">登录</el-button>
</el-form-item>
</el-form>
</div>
</template>
步骤2:使用定时器禁用按钮
<script>
export default {
data() {
return {
text: '发送验证码',//按钮显示
time: 60,//设置按钮时间,即验证码时间
timer: null,//定时器
disable: false,//是否禁用
formInline: {authPhone: "", authCode: ""},
rules: {
authPhone: [
{required: true, message: '请输入手机号', trigger: 'blur'},
], authCode: [
{required: true, message: '请输入验证码', trigger: 'blur'},
],
}
}
}, methods: {
handleSend() {
//校验手机号格式
let regTel = /^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}$/;
if (!regTel.test(this.formInline.authPhone)) {
this.$message.error("请输入正确的手机号格式");
return false;
}
axios.post("http://localhost:8101/auth/sendCode?phone=" + this.formInline.authPhone).then(() => {
//按钮开启禁用
this.disable = true
//提示剩余时间
this.text = this.time + 's后重新发送'
//启用定时器
this.timer = setInterval(() => {
//如果时间不为0,那么显示剩余时间,如果结束显示重新发送
if (this.time > 0) {
this.time--
this.text = this.time + 's后重新发送'
} else {
//停止定时器
clearInterval(this.timer)
this.time = 60
this.disable = false
this.text = '重新发送'
}
}, 1000)
})
}, submitForm(formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
axios.post("http://localhost:8101/auth/loginByCode", this.formInline).then(r => {
// noinspection JSCheckFunctionSignatures
setCookie("token", r.data.data);
this.$router.push("list");
})
} else {
console.log('error submit!!');
return false;
}
});
}
}, created() {
const time = localStorage.getItem('time')
if (time && time > 0) {
this.text = time + 's后重新发送'
this.time = time
this.handleSend()
}
}
}
</script>
步骤3:使用榛子云发送短信
/**
* 获取验证码
*/
@RequestMapping("sendCode")
public R sendCode(@RequestParam("phone") String phone) {
// 随机生成6位数验证码
String code = RandomUtil.randomString("1234567890", 6);
// 查询是否已存在验证码,如果未存在验证码则发送验证码
if (!redisTemplate.hasKey("key-" + phone)) {
// 获取榛子云客户端
ZhenziSmsClient client = new ZhenziSmsClient(MyConfig.appUrl, MyConfig.appId, MyConfig.appSecret);
// 构建参数集合
HashMap<String, Object> map = new HashMap<>();
// 接收到短信的手机号
map.put("number", phone);
// 榛子云短信模板"2"
map.put("templateId", MyConfig.templateIdTwo);
// 新建长度为"1"的数组
String[] templateParams = new String[1];
// 为第"1"个参数,赋值
templateParams[0] = code;
// 榛子云短信模板"2"参数
map.put("templateParams", templateParams);
try {
// 发送短信
String send = client.send(map);
} catch (Exception e) {
// 发送失败
return R.failed("验证码发送失败");
}
// 将验证码存入redis,设置结束时间为60秒
redisTemplate.opsForValue().set("key-" + phone, code, 60, TimeUnit.SECONDS);
// 短信发送成功
return R.successed("验证码发送成功");
} else {
// 获取剩余时间
Long expireTime = redisTemplate.getExpire("key-" + phone);
return R.failed("验证码已发送,请" + expireTime + "秒后再试");
}
}
注:MyConfig仅个人配置,若有需要请访问榛子云官方网站
步骤4:后端校验
/**
* 验证码登录
*/
@RequestMapping("loginByCode")
public R loginByCode(Auth user) {
Object code = redisTemplate.opsForValue().get("key-" + user.getAuthPhone());// 通过手机号获取redis中验证码
if (code == null) {
// 如果验证码为null则提醒用户重新发送
return R.failed("请重新发送验证码");
}
if (!StrUtil.equalsIgnoreCase(code.toString(), user.getAuthCode())) {
// 如果验证码不为空但与redis存储的验证码不符则提示验证码错误
return R.failed("验证码错误");
}
// 查询用户信息
QueryWrapper<Auth> wrapper = new QueryWrapper<>();
// 通过"手机号"查询用户
wrapper.eq("auth_phone", user.getAuthPhone());
// 获取查询到的用户信息
Auth one = authService.getOne(wrapper);
// 判断用户是否存在
if (one == null) {
// 通过雪花算法为用户"盐"赋值
user.setSalt(IdUtil.getSnowflake().nextIdStr());
// 等待用户设置密码
user.setAuthPwd(null);
// 添加用户信息到数据库
authService.save(user);
one = user;
}
// 加密签名
byte[] key = one.getSalt().getBytes();
// 通过用户id获取Token
String token = JWT.create().setPayload("id", user.getAuthId()).setKey(key).sign();
return R.successed(token);
}
附带:榛子云配置解析
/**
* 榛子云配置
*/
public static final String appId = "******";
public static final String appSecret = "********-****-****-****-************";
public static final String appUrl = "https://sms_developer.zhenzikj.com";
public static final String templateIdOne = "*****";// 验证码
public static final String templateIdTwo = "*****";// 新年祝福