当前位置: 首页 > news >正文

谷粒商城实战笔记-214~219-商城业务-认证服务-验证码防刷校验

文章目录

  • 一,验证码防刷校验
    • 1,第三方服务提供发送短信的接口
    • 2,登录服务提供给前端的接口
  • 二,215-商城业务-认证服务-一步一坑的注册页环境
  • 三,商城业务-认证服务-异常机制
  • 四,217-商城业务-认证服务-MD5&盐值&BCrypt
  • 五,218-商城业务-认证服务-注册完成
  • 六,219-商城业务-认证服务-账号密码登录完成
  • 总结

包含:

  • 214-商城业务-认证服务-验证码防刷校验
  • 215-商城业务-认证服务-一步一坑的注册页环境
  • 216-商城业务-认证服务-异常机制
  • 217-商城业务-认证服务-MD5&盐值&BCrypt
  • 218-商城业务-认证服务-注册完成
  • 219-商城业务-认证服务-账号密码登录完成

一,验证码防刷校验

1,第三方服务提供发送短信的接口

短信服务可以给多方提供服务,所以要提供一个接口,接受电话号码和code,调用接口将code发送给指定的电话号码。

@Controller
@RequestMapping(value = "/sms")
public class SmsSendController {@Resourceprivate SmsComponent smsComponent;/*** 提供给别的服务进行调用* @param phone* @param code* @return*/@GetMapping(value = "/sendCode")public R sendCode(@RequestParam("phone") String phone, @RequestParam("code") String code) {//发送验证码smsComponent.sendCode(phone,code);return R.ok();}}

2,登录服务提供给前端的接口

@Controller
public class LoginController {@Resourceprivate ThirdPartFeignService thirdPartFeignService;@Autowiredprivate StringRedisTemplate stringRedisTemplate;@ResponseBody@GetMapping(value = "/sms/sendCode")public R sendCode(@RequestParam("phone") String phone) {//1、接口防刷String redisCode = stringRedisTemplate.opsForValue().get(AuthServerConstant.SMS_CODE_CACHE_PREFIX + phone);if (StrUtil.isNotEmpty(redisCode)) {//活动存入redis的时间,用当前时间减去存入redis的时间,判断用户手机号是否在60s内发送验证码long currentTime = Long.parseLong(redisCode.split("_")[1]);if (System.currentTimeMillis() - currentTime < 60000) {//60s内不能再发return R.error(BizCodeEnum.SMS_CODE_EXCEPTION.getCode(),BizCodeEnum.SMS_CODE_EXCEPTION.getMessage());}}//2、验证码的再次效验 redis.存key-phone,value-codeint code = (int) ((Math.random() * 9 + 1) * 100000);String codeNum = String.valueOf(code);String redisStorage = codeNum + "_" + System.currentTimeMillis();//存入redis,防止同一个手机号在60秒内再次发送验证码stringRedisTemplate.opsForValue().set(AuthServerConstant.SMS_CODE_CACHE_PREFIX+phone,redisStorage,10, TimeUnit.MINUTES);thirdPartFeignService.sendCode(phone, codeNum);return R.ok();}}

这段代码用于共前端调用,发送短信验证码,其主要作用如下:

  1. 接口防刷机制:首先检查Redis中是否已经为提供的手机号码phone存储了验证码。如果存在,并且当前时间与存储验证码时的时间差小于60秒,则认为请求过于频繁,返回错误信息,阻止用户在短时间内重复发送验证码。

  2. 生成验证码:如果用户请求发送验证码的频率正常,代码将生成一个六位数的随机验证码。

  3. 存储验证码到Redis:将生成的验证码和当前时间戳拼接,存储到Redis中,其中键为手机号码,值为验证码和时间戳的组合。这用于验证验证码的有效性,并防止同一个手机号在60秒内再次发送验证码。

  4. 调用第三方服务发送验证码:通过Feign服务调用第三方服务(例如短信服务提供商)发送验证码到用户的手机上。

  5. 返回操作结果:如果验证码发送成功,方法返回一个表示操作成功的响应。

关于发送验证的两个要点:

  • 1,因为要验证用户输入的验证码是否正确,需要后台将生成的验证码进行保存,因为不需要持久化,所以保存在redis中。
  • 2,为了防止恶意调用,所以要在后台进行验证,60秒内只能调用一次,超过一次的返回错误,不允许重发。

二,215-商城业务-认证服务-一步一坑的注册页环境

这一节的主要内容是:

  • 校验前端登录参数是否符合标准
  • 如果不符合校验规则,将错误信息返回给前端,由前端回显

封装前端参数的VO,VO使用了JSR303校验,简化代码。

@Data
public class UserRegisterVo {@NotEmpty(message = "用户名不能为空")@Length(min = 6, max = 19, message="用户名长度在6-18字符")private String userName;@NotEmpty(message = "密码必须填写")@Length(min = 6,max = 18,message = "密码必须是6—18位字符")private String password;@NotEmpty(message = "手机号不能为空")@Pattern(regexp = "^[1]([3-9])[0-9]{9}$", message = "手机号格式不正确")private String phone;@NotEmpty(message = "验证码不能为空")private String code;}

这里有个小细节,前端登录界面登录请求会携带参数,校验不通过,需要把错误信息返回给前端,因为使用了了模板引擎,课程中采用请求转发的方式,实际上在直接返回错误信息应该也是可以的,只要前端做好适配。

三,商城业务-认证服务-异常机制

登录请求的参数校验通过后,需要验证验证码是否正确,从redis中取出存储的验证码,然后校验即可。

如果验证码校验通过,下一步要调用member会员服务的接口,注册会员。

会员服务提供的这个接口中,需要做一些校验:

  • 用户名要唯一
  • 手机号要唯一

如果校验不通过,通过抛异常的方式将信息抛给controller层。

四,217-商城业务-认证服务-MD5&盐值&BCrypt

对于用户的密码,不能存储明文,必须对其进行加密。

加密有两种方式:

  • 不可逆的加密,不能根据密文推出明文
  • 可逆的加密,可以根据密文推出密文
  • 为了防止相同的密码有相同的密文,通常采用加盐的方式,这样即使多个用户的密码相同,存储在数据库的密文也不是一样的

课程中采用不可逆的加密,在实际工作中一般也采用不可逆的加密。

MD5是常用的不可逆加密算法,我们使用Spring提供的工具类BCryptPasswordEncoder 对密码进行md5加密。

		BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();String encode = bCryptPasswordEncoder.encode(vo.getPassword());memberEntity.setPassword(encode);

MD5(Message Digest Algorithm 5,信息摘要算法5)是一种广泛使用的加密算法,用于生成数据的哈希值。

  1. 压缩性:无论输入数据的长度如何,MD5算法都会生成一个固定长度(128位,即16字节)的哈希值。

  2. 易于计算:从原始数据计算出MD5值是一个相对简单和快速的过程。

  3. 抗修改性:对原始数据进行任何微小的改动,哪怕是修改一个字符,都会导致生成的MD5值发生显著的变化。

  4. 强抗碰撞性:找到两个不同的数据输入,它们具有相同的MD5值,被认为是非常困难的。但是,这并不意味着MD5没有碰撞,实际上,MD5的抗碰撞性已经被证明是不足够的,尤其是在密码学领域。

  5. 加盐(Salting):为了增加MD5的安全性,可以通过添加一个随机生成的盐值(Salt)与原始数据组合,然后进行MD5加密。数据库中存储加密后的MD5值和盐值。在验证数据时,使用相同的盐值对输入数据进行MD5加密,然后与存储的MD5值进行比较以验证正确性。

五,218-商城业务-认证服务-注册完成

这一节主要调试注册服务的完成。

六,219-商城业务-认证服务-账号密码登录完成

这一节生完成登录的后台接口,主要的逻辑:

  • 权限认知服务接收前端页面的参数
  • 校验通过后调用会员服务的接口,接口根据参数查询数据库,判断用户名和密码是否正确

总结

  1. 错误处理:首先检查表单验证结果result是否有错误。如果有错误,将错误信息收集并存储到errors映射中,然后重定向回注册页面。

  2. 验证码验证:从前端获取用户输入的验证码code,然后从Redis中获取存储的验证码redisCode。如果Redis中有对应的验证码,并且用户输入的验证码与Redis中的验证码匹配,则进行下一步。

  3. 删除验证码:如果验证码匹配,从Redis中删除该验证码,防止重复使用。

  4. 远程服务注册:调用远程服务memberFeignService.register(vos)进行用户注册。

  5. 注册结果处理

    • 如果注册成功(register.getCode() == 0),重定向到登录页面。
    • 如果注册失败,收集错误信息,存储到errors映射中,然后重定向回注册页面。
  6. 验证码不匹配或不存在处理:如果用户输入的验证码与Redis中的不匹配,或者Redis中没有对应的验证码,收集错误信息,存储到errors映射中,然后重定向回注册页面。

整体上,这段代码实现了用户注册时的验证码验证、错误处理和注册结果反馈,确保了注册流程的安全性和用户体验。

http://www.lryc.cn/news/426532.html

相关文章:

  • 在华为服务器的openEuler系统中适配Pytorch调用NPU
  • MVCC工作原理深入解析
  • 使用html+css+js实现完整的登录注册页面
  • 2024年8月16日(运维自动化 ansible)
  • 荣耀Magicbook x14 扩容1TB固态
  • Springboot整合全文检索引擎Lucene
  • 【深度学习】【语音】TTS, 如何使用Python分析WAV的采样率、比特深度、通道数
  • Linux的安装和使用
  • 查看一个exe\dll文件的依赖项
  • 高校科研信息管理系统pf
  • Linux 开机自动挂载共享文件设置
  • c_cpp_properties.json、launch.json、 tasks.json
  • mysql 一些知识点 面试用
  • STM32之点亮LED灯
  • Java 多线程练习2 (抽奖比较Runnable写法)
  • 使用fastboot更新部分系统
  • windows 加载portch遇到的错误
  • 如何将 CICD 模版重构为 CICD component?
  • 数学建模——评价决策类算法(层次分析法、Topsis)
  • KEEPALIVED 全csdn最详细----理论+实验(干货扎实,包教会的)
  • 微信云开发云存储全部下载
  • vos3000怎样对接voip落地语音网关呢?卡机和O口网关的配置技巧有哪些?
  • MySQL数据库专栏(四)数据库操作
  • Python编写Word文档
  • 聚星文社AI工具
  • 思科OSPF动态路由配置8
  • C++(10)类语法分析(1)
  • python语言day6 os random datetime .ini文件
  • powershell 终端 执行 pnpm -v报错
  • 最新保姆级Anaconda和Pycharm安装激活过程(2024最新版本)