用户注册这样玩,保你平安
当前位置:点晴教程→知识管理交流
→『 技术文档交流 』
前言基本上每个系统系统都包含用户注册、发送验证码等基本操作。在前些年,我还记得我在逛 csdn、贴吧、网易新闻等网站的时候是可以不登陆也能浏览完网页内容的,但是近几年这些网站已经改成了不登陆不让用,浏览网页时不时提醒你要进行登录,对于一些不喜欢注册的用户造成了相当大的困扰。 但是不知道大家有没有想过这里面的深层逻辑,就是为什么前些年什么 csdn、贴吧、网易新闻等明明不进行登录浏览网页体验还行,现在要改成这样子? 这里面涉及的因素有很多,比如互联网发展到头、变现困难、存量环境加剧内卷等。 当公司盈利压力变大,老板眼看收益日趋降低,便开始拉领导开会,领导开完会开始 PUA 员工,一层一层递进,辅以绩效、okr 等工具制定目标结果。于是公司底层员工的想法从努力赚钱、升职加薪变成保住饭碗、养活一家老小,对于业务上的月度、季度营收要求自然是各种促进用户付费的手段应上齐上。 这里面提升付费有一个非常重要的前提就是用户,只要有了用户就有付费希望。 如果用户不注册,不留下手机号、邮箱等个人信息,互联网运营又怎么给这些用户发送营销短信和邮件。所以说强制注册本质上是为了公司利益。 只要把用户留下来,留在自己的 APP 里,收集用户信息,后续各种运营活动、支付弹窗、短信找回、活动抽奖一起上,何愁没有用户 😜。
OK,到这里题外话说多了,虽然说用户注册是一个很基本的逻辑,但是很多人一不小心就会掉坑里。这里我给大家介绍下 waynboot-mall 项目中用户注册是怎么玩的,为什么说可以保你平安。
用户注册在 waynboot-mall 项目中,商城注册页面截图如下。 /captcha 生成图形验证码接口@ResponseBody @RequestMapping("/captcha") public R captcha() { // 1. 创建验证码对象,定义验证码图形的长、宽、以及字数 SpecCaptcha specCaptcha = new SpecCaptcha(80, 32, 4); // 2. 生成验证码 String verCode = specCaptcha.text().toLowerCase(); // 3. 生成验证码唯一key String captchaKey = IdUtil.getUid(); // 4. 存入redis并设置过期时间为30分钟 redisCache.setCacheObject(captchaKey, verCode, SysConstants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES); // 5. 将key和base64返回给前端 return R.success().add("captchaKey", captchaKey).add("image", specCaptcha.toBase64()); } 验证码接口基本是每个系统都有的接口,验证码主要是为了防止别人直接调用接口进行注册操作,是一个安全措施。现在市面上流行的有图形验证码、滑块验证码、点选验证码等,waynboot-mall 项目中使用的图形验证码,大家有兴趣可以了解 tianai-captcha 这个项目,包含滑块验证码、点选验证码等。现在我们对验证码接口进行讲解,
前端在调用完 /captcha 接口后,会拿到 captchaKey 以及验证码图像的 base64 编码,之后前端就可以将 base64 编码作为 img 标签 src 属性用作图形验证码展示。 用户输入邮箱和图形验证码后就可以点击发送邮箱验证码了。 调用发送邮箱验证码接口时会将 captchaKey、验证码、手机号等信息一起传给服务端。 /sendEmailCode 发送邮箱验证码接口@PostMapping("/sendEmailCode") public R sendEmailCode(@RequestBody RegistryObj registryObj) { String captchaKey = registryObj.getCaptchaKey(); String captchaCode = registryObj.getCaptchaCode(); String mobile = registryObj.getMobile(); if (StringUtils.isBlank(captchaKey)) { return R.error(CUSTOM_ERROR.setMsg("图形验证码错误")); } if (StringUtils.isBlank(captchaCode)) { return R.error(CUSTOM_ERROR.setMsg("图形验证码为空")); } if (StringUtils.isBlank(mobile)) { return R.error(CUSTOM_ERROR.setMsg("手机号为空")); } String redisCode = redisCache.getCacheObject(captchaKey); // 判断验证码code if (!redisCode.equals(captchaCode.trim().toLowerCase())) { return R.error(USER_CAPTCHA_CODE_ERROR); } // 验证手机号是否唯一 long count = iMemberService.count(Wrappers.lambdaQuery(Member.class).eq(Member::getMobile, mobile)); if (count > 0) { return R.error(USER_PHONE_HAS_REGISTER_ERROR); } // 生成邮箱验证码code String emailCode = RandomUtil.randomString(6); // 生成邮箱验证码唯一key String emailKey = RedisKeyEnum.EMAIL_KEY_CACHE.getKey(IdUtil.getUid()); // 存入redis并设置过期时间为20分钟 redisCache.setCacheObject(emailKey, emailCode + "_" + mobile, RedisKeyEnum.EMAIL_KEY_CACHE.getExpireSecond()); commonThreadPoolTaskexecutor.execute(() -> { EmailConfig emailConfig = mailConfigService.getById(1L); SendMailVO sendMailVO = new SendMailVO(); sendMailVO.setSubject("mall商城注册通知"); sendMailVO.setContent("邮箱验证码:" + emailCode); sendMailVO.setTos(Collections.singletonList(registryObj.getEmail())); MailUtil.sendMail(emailConfig, sendMailVO, false, false); }); return R.success().add("emailKey", emailKey); } 一般商城系统中,发送邮箱验证码、短信验证码时都需要进行验证码输入这一步骤,这是为了防止别人直接通过接口调用的形式,浪费我们系统的资源,特别是发送手机验证码、邮件这种资源。发送邮箱验证码接口讲解如下,
前端在调用完 /sendEmailCode 接口后,就可以拿到 emailKey。 这样等用户输入邮箱里的验证码后,点击注册按钮,我们就可能正式开始注册操作了。 /registry 用户注册@PostMapping("/registry") public R registry(@RequestBody RegistryObj registryObj) { // 验证两次密码输入是否一致 if (!StringUtils.equalsIgnoreCase(registryObj.getPassword(), registryObj.getConfirmPassword())) { return R.error(USER_TWO_PASSWORD_NOT_SAME_ERROR); } // 验证用户手机号是否唯一 long count = iMemberService.count(Wrappers.lambdaQuery(Member.class).eq(Member::getMobile, registryObj.getMobile())); if (count > 0) { return R.error(USER_PHONE_HAS_REGISTER_ERROR); } // 判断图形验证码 String redisCaptchaCode = redisCache.getCacheObject(registryObj.getCaptchaKey()); if (registryObj.getCaptchaCode() == null || !redisCaptchaCode.equals(registryObj.getCaptchaCode().trim().toLowerCase())) { return R.error(USER_CAPTCHA_CODE_ERROR); } // 判断邮箱验证码 String value = redisCache.getCacheObject(registryObj.getEmailKey()); String[] split = value.split("_"); if (split.length < 2) { return R.error(ReturnCodeEnum.USER_EMAIL_CODE_ERROR); } String redisEmailCode = split[0]; String mobile = split[1]; // 判断发送邮箱验证码的手机号是否与用户当前传入手机号一致 if (!StringUtils.equalsIgnoreCase(mobile, registryObj.getMobile())) { return R.error(ReturnCodeEnum.USER_REGISTER_MOBILE_ERROR); } // 判断用户输入邮箱验证码是否正确 if (registryObj.getEmailCode() == null || !redisEmailCode.equals(registryObj.getEmailCode().trim().toLowerCase())) { return R.error(ReturnCodeEnum.USER_EMAIL_CODE_ERROR); } // 删除验证码 redisCache.deleteObject(registryObj.getCaptchaKey()); redisCache.deleteObject(registryObj.getEmailKey()); Member member = new Member(); long time = System.currentTimeMillis(); member.setNickname("昵称" + time / 1000); String avatar = SysConstants.DEFAULT_AVATAR; member.setAvatar(avatar); member.setMobile(registryObj.getMobile()); member.setEmail(registryObj.getEmail()); member.setPassword(SecurityUtils.encryptPassword(registryObj.getPassword())); member.setcreateTime(new Date()); return R.result(iMemberService.save(member)); } 注册接口,需要逻辑完善,所以这里的校验逻辑会比较多,因为一个商城最重要的几个接口就是注册、登录、下单、支付等。 除了能让用户正常注册外,有时候还需要确保用户一个手机号只能注册一个账号,完成对用户手机号在商城的唯一性保障。除了先查询用户手机号是否已存在外,还需要对用户 member 表的手机号字段设置唯一索引来完成。注册接口讲解如下,
最后聊两句用户注册说简单是很简单,但是校验逻辑一定要做好!这是我的踩坑经验,现在我传授给你,希望能帮你平安🤝。 作者:waynaqua 原文链接:https://www.cnblogs.com/waynaqua/p/17868631.html 该文章在 2023/12/1 14:18:52 编辑过 |
关键字查询
相关文章
正在查询... |