用戶注冊這樣玩,保你平安
當前位置:點晴教程→知識管理交流
→『 技術文檔交流 』
前言基本上每個系統系統都包含用戶注冊、發送驗證碼等基本操作。在前些年,我還記得我在逛 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 編輯過 |
關鍵字查詢
相關文章
正在查詢... |