java短信验证码登录功能设计与实现
⽬录
前⾔
业务案例
业务关键点剖析
短信验证码功能实现思路
有效期问题
操作步骤
前⾔
现在不管是各类的⽹站,还是⼤⼩社交app,登录⽅式是越来越多了,其中基于短信验证码的登录可以说是各类app必不可少的⽅式,短信验证码登录以其⾼效,安全,便捷等特性受到许多⽤户的青睐
业务案例
如下所⽰,是⼀个⼤家熟知的采⽤短信登录的⼊⼝
输⼊⼿机号之后,出现如下效果,
输⼊⼿机上⾯收到的验证码之后,就可以正常登录了
业务关键点剖析
以上是⼀个正常的使⽤短信验证码登录的业务流程,在实际开发中,需要考虑的因素更多了,⽐如:
验证码位数如何
验证码如何存储
如何预防短信被刷
倒计时功能,前后端如何配合
其实来说,短信验证码功能并不难,难得是如何做到业务场景的全⾯覆盖和功能细节上⾯的考虑
短信验证码功能实现思路
⼩编结合实际经验和调研,⽬前⽐较流⾏的做法是,使⽤redis做短信验证码,想必说到这⾥,懂⾏的同学们应该猜到了
完整的业务逻辑⼤概如下:
依据这个业务逻辑的实现思路,我们⼤致可以理清代码的编写逻辑,在⼩编开发过程中,其中有⼀个点遇到了⼀点梗,就是关于验证码的有效期的问题,主要考虑下⾯2点:
后端存储验证码有效期时长
前端页⾯倒计时和后端有效期的关系
有效期问题
下⾯我们编写代码来演⽰下完整的过程
前置准备:搭建⼀个springboot⼯程
操作步骤
1、导⼊核⼼依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.2.1.RELEASE</version>
</dependency>
@Service
public class SmsServiceImpl implements SmsService {
public static final String VERIFY_CODE = "login:verify_code:";
@Autowired
private DbUserMapper dbUserMapper;
@Autowired
private RedisTemplate<String,String> redisTemplate;
@Override
public String getSmsVerifyCode(String phone) {
if (StringUtils.isEmpty(phone)) {
throw new RuntimeException("⽤户⼿机号为空");
}
QueryWrapper queryWrapper = new QueryWrapper();
queryWrapper.eq("mobile",phone);
DbUser dbUser = dbUserMapper.selectOne(queryWrapper);
if(dbUser == null){
throw new RuntimeException("⽤户不存在");
}
String smsVerifyCode = getSmsVerifyCode();
String smsCodeKey = VERIFY_CODE + UserId();
String existedSmsCode = redisTemplate.opsForValue().get(smsCodeKey);
//如果验证码已经存在时
if (StringUtils.isNotEmpty(existedSmsCode)) {
Long expireTime = redisTemplate.opsForValue().getOperations().getExpire(smsCodeKey);
long lastTime = 60 * 3 - expireTime;
//三分钟内验证码有效,1分钟到3分钟之间,⽤户可以继续输⼊验证码,也可以重新获取验证码,新的验证码将覆盖旧的 if(lastTime > 60 && expireTime >0){
//调⽤第三⽅平台发短信,只有短信发送成功了,才能将短信验证码保存到redis
System.out.println("此处调⽤短信发送逻辑......");
redisTemplate.opsForValue().set(smsCodeKey, smsVerifyCode, 60 * 3, TimeUnit.SECONDS);
System.out.println("短信验证码:" + smsVerifyCode);
}
//⼀分钟之内不得多次获取验证码
if(lastTime < 60){
throw new RuntimeException("操作过于频繁,请⼀分钟之后再次点击发送");
}
}else {
//调⽤notify服务,只有notify的短信发送成功了,才能将短信验证码保存到redis
html怎么实现登录验证功能System.out.println("此处调⽤短信发送逻辑......");
System.out.println("短信验证码:" + smsVerifyCode);
redisTemplate.opsForValue().set(smsCodeKey, smsVerifyCode, 60 * 3, TimeUnit.SECONDS);
}
return smsVerifyCode;
}
/**
* 随机获取6位短信数字验证码
*
* @return
*/
public static String getSmsVerifyCode() {
Random random = new Random();
String code = "";
for (int i = 0; i < 6; i++) {
int rand = Int(10);
code += rand;
}
return code;
}
}
⾸次输⼊⼿机号,获取验证码时,后端设置验证码有效期为3分钟,前端倒计时1分钟
1分钟之内,⽤户不能第⼆次获取验证码,1分钟之后,⽤户可以重新获取验证码
超过1分钟后,同⼀个⽤户再次点击获取验证码时,后端需主动移除redis存储的上⼀次验证码
3分钟有效期内,⽤户可随时输⼊第⼀次的验证码进⾏登录
登录成功后,登录接⼝需主动移除redis中的验证码
以上为验证码的核⼼业务⽅法,下⾯再编写⼀个登录的⽅法,当基础校验和验证码校验通过后,即可登录 @Override
public String login(String userId, String smsCode) {
if (StringUtils.isEmpty(userId)) {
throw new RuntimeException("⽤户ID必传");
}
if (StringUtils.isEmpty(smsCode)) {
throw new RuntimeException("验证码不能为空");
}
QueryWrapper queryWrapper = new QueryWrapper();
queryWrapper.eq("user_id",userId);
DbUser dbUser = dbUserMapper.selectOne(queryWrapper);
if(dbUser == null){
throw new RuntimeException("⽤户不存在");
}
//校验验证码
String smsCodeKey = VERIFY_CODE + UserId();
String verifyCode = redisTemplate.opsForValue().get(smsCodeKey);
if (StringUtils.isEmpty(verifyCode)) {
throw new RuntimeException("短信验证码不存在或已过期");
}
if (!StringUtils.equals(smsCode, verifyCode)) {
throw new RuntimeException("短信验证码错误");
}
/
/TODO 其他待验证的登录业务逻辑
System.out.println("执⾏其他业务......");
System.out.println("登录成功");
//最后清理下验证码
if(redisTemplate.hasKey(smsCodeKey)){
redisTemplate.delete(smsCodeKey);
}
return "login success";
}
@RestController
public class SmsController {
@Autowired
private SmsService smsService;
@GetMapping("get/sms_code")
public String getSmsVerifyCode(@RequestParam("phone") String phone){
SmsVerifyCode(phone);
}
/**
* 登录
* @param userId
* @param smsCode
* @return
*/
@GetMapping("/login")
public String login(@RequestParam("userId") String userId,@RequestParam("smsCode") String smsCode){ return smsService.login(userId,smsCode);
}
}
启动redis服务,启动项⽬,数据库提前准备⼀条数据
场景测试1:获取验证码
调⽤登录接⼝,使⽤上⾯的验证码:
场景测试2:1分钟内多次获取验证码
第⼀次获取验证码
再次获取验证码
超过1分钟少于3分钟内,再次获取验证码,得到新的验证码,同时redis中存储的是最新的验证码
场景测试3:登录输⼊错误验证码
总体来说,使⽤redis实现短信验证码登录的功能不算太复杂,主要是需要全⾯的考虑到各⾃使⽤场景即可
到此这篇关于java短信验证码登录功能设计与实现的⽂章就介绍到这了,更多相关java短信验证码登录内容请搜索以前的⽂章或继续浏览下⾯的相关⽂章希望⼤家以后多多⽀持!
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论