自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

用戶注冊(cè)這樣玩,保你平安

開(kāi)發(fā) 前端
除了能讓用戶正常注冊(cè)外,有時(shí)候還需要確保用戶一個(gè)手機(jī)號(hào)只能注冊(cè)一個(gè)賬號(hào),完成對(duì)用戶手機(jī)號(hào)在商城的唯一性保障。

前言

基本上每個(gè)系統(tǒng)系統(tǒng)都包含用戶注冊(cè)、發(fā)送驗(yàn)證碼等基本操作。在前些年,我還記得我在逛 csdn、貼吧、網(wǎng)易新聞等網(wǎng)站的時(shí)候是可以不登陸也能瀏覽完網(wǎng)頁(yè)內(nèi)容的,但是近幾年這些網(wǎng)站已經(jīng)改成了不登陸不讓用,瀏覽網(wǎng)頁(yè)時(shí)不時(shí)提醒你要進(jìn)行登錄,對(duì)于一些不喜歡注冊(cè)的用戶造成了相當(dāng)大的困擾。

但是不知道大家有沒(méi)有想過(guò)這里面的深層邏輯,就是為什么前些年什么 csdn、貼吧、網(wǎng)易新聞等明明不進(jìn)行登錄瀏覽網(wǎng)頁(yè)體驗(yàn)還行,現(xiàn)在要改成這樣子?

這里面涉及的因素有很多,比如互聯(lián)網(wǎng)發(fā)展到頭、變現(xiàn)困難、存量環(huán)境加劇內(nèi)卷等。

當(dāng)公司盈利壓力變大,老板眼看收益日趨降低,便開(kāi)始拉領(lǐng)導(dǎo)開(kāi)會(huì),領(lǐng)導(dǎo)開(kāi)完會(huì)開(kāi)始 PUA 員工,一層一層遞進(jìn),輔以績(jī)效、okr 等工具制定目標(biāo)結(jié)果。于是公司底層員工的想法從努力賺錢(qián)、升職加薪變成保住飯碗、養(yǎng)活一家老小,對(duì)于業(yè)務(wù)上的月度、季度營(yíng)收要求自然是各種促進(jìn)用戶付費(fèi)的手段應(yīng)上齊上。

這里面提升付費(fèi)有一個(gè)非常重要的前提就是用戶,只要有了用戶就有付費(fèi)希望。

如果用戶不注冊(cè),不留下手機(jī)號(hào)、郵箱等個(gè)人信息,互聯(lián)網(wǎng)運(yùn)營(yíng)又怎么給這些用戶發(fā)送營(yíng)銷(xiāo)短信和郵件。所以說(shuō)強(qiáng)制注冊(cè)本質(zhì)上是為了公司利益。

只要把用戶留下來(lái),留在自己的 APP 里,收集用戶信息,后續(xù)各種運(yùn)營(yíng)活動(dòng)、支付彈窗、短信找回、活動(dòng)抽獎(jiǎng)一起上,何愁沒(méi)有用戶 ??。

用戶信息記錄的意義是為了聚集 C 端用戶、收集信息,為后續(xù)運(yùn)營(yíng)活動(dòng)(提升付費(fèi))做準(zhǔn)備。就拿淘寶舉例,個(gè)性化推薦、千人千面、雙 11 活動(dòng)等,這一系列運(yùn)營(yíng)活動(dòng)說(shuō)到底都是為了提升淘寶的付費(fèi)金額,提升淘寶平臺(tái)的 GMV。什么個(gè)性化推薦、千人千面說(shuō)白了就是收集你的個(gè)人信息,你的商品點(diǎn)擊、瀏覽、下單等操作都會(huì)被淘寶采集,進(jìn)而通過(guò)算法模型進(jìn)行商品推薦,選出你可能感興趣的商品展示,從而提升淘寶付費(fèi)金額。

OK,到這里題外話說(shuō)多了,雖然說(shuō)用戶注冊(cè)是一個(gè)很基本的邏輯,但是很多人一不小心就會(huì)掉坑里。這里我給大家介紹下 waynboot-mall 項(xiàng)目中用戶注冊(cè)是怎么玩的,為什么說(shuō)可以保你平安。

waynboot-mall 項(xiàng)目是由我開(kāi)源的一套 H5 商城項(xiàng)目,包含運(yùn)營(yíng)后臺(tái)、H5 商城前臺(tái)和服務(wù)端接口。實(shí)現(xiàn)了商城所需的首頁(yè)展示、商品分類、商品詳情、商品 sku、分詞搜索、購(gòu)物車(chē)、結(jié)算下單、支付寶/微信支付、收單評(píng)論以及完善的后臺(tái)管理等一系列功能。技術(shù)上基于最新得 Springboot3.0 框架開(kāi)發(fā)而來(lái),整合了 MySql、Redis、RabbitMQ、ElasticSearch 等常用中間件。商城模塊劃分合理、代碼質(zhì)量較高、易于部署,非常適合大家拿來(lái)學(xué)習(xí)使用。

github 地址:https://github.com/wayn111/waynboot-mall

用戶注冊(cè)

在 waynboot-mall 項(xiàng)目中,商城注冊(cè)頁(yè)面截圖如下。

圖片圖片

/captcha 生成圖形驗(yàn)證碼接口

@ResponseBody
@RequestMapping("/captcha")
public R captcha() {
    // 1. 創(chuàng)建驗(yàn)證碼對(duì)象,定義驗(yàn)證碼圖形的長(zhǎng)、寬、以及字?jǐn)?shù)
    SpecCaptcha specCaptcha = new SpecCaptcha(80, 32, 4);
    // 2. 生成驗(yàn)證碼
    String verCode = specCaptcha.text().toLowerCase();
    // 3. 生成驗(yàn)證碼唯一key
    String captchaKey = IdUtil.getUid();
    // 4. 存入redis并設(shè)置過(guò)期時(shí)間為30分鐘
    redisCache.setCacheObject(captchaKey, verCode, SysConstants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES);
    // 5. 將key和base64返回給前端
    return R.success().add("captchaKey", captchaKey).add("image", specCaptcha.toBase64());
}

驗(yàn)證碼接口基本是每個(gè)系統(tǒng)都有的接口,驗(yàn)證碼主要是為了防止別人直接調(diào)用接口進(jìn)行注冊(cè)操作,是一個(gè)安全措施?,F(xiàn)在市面上流行的有圖形驗(yàn)證碼、滑塊驗(yàn)證碼、點(diǎn)選驗(yàn)證碼等,waynboot-mall 項(xiàng)目中使用的圖形驗(yàn)證碼,大家有興趣可以了解 tianai-captcha 這個(gè)項(xiàng)目,包含滑塊驗(yàn)證碼、點(diǎn)選驗(yàn)證碼等。現(xiàn)在我們對(duì)驗(yàn)證碼接口進(jìn)行講解,

  • 第一步,創(chuàng)建驗(yàn)證碼對(duì)象,定義驗(yàn)證碼圖形的長(zhǎng)、寬、以及字?jǐn)?shù)(這里創(chuàng)建的 SpecCaptcha 對(duì)象來(lái)自 easy-captcha 項(xiàng)目)
  • 第二步,生成驗(yàn)證碼 verCode
  • 第三步,為驗(yàn)證碼生成唯一 captchaKey
  • 第四步,將 captchaKey 作為 key, verCode 作為 value,存入 redis 并設(shè)置過(guò)期時(shí)間
  • 第五步,將 captchaKey 以及驗(yàn)證碼圖像的 base64 編碼返回給前端

圖片圖片

前端在調(diào)用完 /captcha 接口后,會(huì)拿到 captchaKey 以及驗(yàn)證碼圖像的 base64 編碼,之后前端就可以將 base64 編碼作為 img 標(biāo)簽 src 屬性用作圖形驗(yàn)證碼展示。

用戶輸入郵箱和圖形驗(yàn)證碼后就可以點(diǎn)擊發(fā)送郵箱驗(yàn)證碼了。

調(diào)用發(fā)送郵箱驗(yàn)證碼接口時(shí)會(huì)將 captchaKey、驗(yàn)證碼、手機(jī)號(hào)等信息一起傳給服務(wù)端。

/sendEmailCode 發(fā)送郵箱驗(yàn)證碼接口

@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("圖形驗(yàn)證碼錯(cuò)誤"));
    }
    if (StringUtils.isBlank(captchaCode)) {
        return R.error(CUSTOM_ERROR.setMsg("圖形驗(yàn)證碼為空"));
    }
    if (StringUtils.isBlank(mobile)) {
        return R.error(CUSTOM_ERROR.setMsg("手機(jī)號(hào)為空"));
    }
    String redisCode = redisCache.getCacheObject(captchaKey);
    // 判斷驗(yàn)證碼code
    if (!redisCode.equals(captchaCode.trim().toLowerCase())) {
        return R.error(USER_CAPTCHA_CODE_ERROR);
    }
    // 驗(yàn)證手機(jī)號(hào)是否唯一
    long count = iMemberService.count(Wrappers.lambdaQuery(Member.class).eq(Member::getMobile, mobile));
    if (count > 0) {
        return R.error(USER_PHONE_HAS_REGISTER_ERROR);
    }
    // 生成郵箱驗(yàn)證碼code
    String emailCode = RandomUtil.randomString(6);
    // 生成郵箱驗(yàn)證碼唯一key
    String emailKey = RedisKeyEnum.EMAIL_KEY_CACHE.getKey(IdUtil.getUid());
    // 存入redis并設(shè)置過(guò)期時(shí)間為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商城注冊(cè)通知");
        sendMailVO.setContent("郵箱驗(yàn)證碼:" + emailCode);
        sendMailVO.setTos(Collections.singletonList(registryObj.getEmail()));
        MailUtil.sendMail(emailConfig, sendMailVO, false, false);
    });
    return R.success().add("emailKey", emailKey);
}

一般商城系統(tǒng)中,發(fā)送郵箱驗(yàn)證碼、短信驗(yàn)證碼時(shí)都需要進(jìn)行驗(yàn)證碼輸入這一步驟,這是為了防止別人直接通過(guò)接口調(diào)用的形式,浪費(fèi)我們系統(tǒng)的資源,特別是發(fā)送手機(jī)驗(yàn)證碼、郵件這種資源。發(fā)送郵箱驗(yàn)證碼接口講解如下,

  • 第一步,校驗(yàn) captchaKey、captchaCode、mobile 必傳參數(shù)
  • 第二步,根據(jù) captchaKey 讀取 redis 中存放的驗(yàn)證碼 code,與用戶輸入 captchaCode 進(jìn)行比較
  • 第三步,驗(yàn)證用戶手機(jī)號(hào)是否唯一
  • 第四步,生成六位郵箱驗(yàn)證碼 emailCode
  • 第五步,生成郵箱驗(yàn)證碼唯一 emailKey
  • 第六步,將 emailKey 作為 key, emailCode_mobile 作為 value,存入 redis 并設(shè)置過(guò)期時(shí)間(注意這一步將用戶手機(jī)號(hào),也存入 Redis 是為了防止用戶在獲取完郵箱驗(yàn)證碼后修改手機(jī)號(hào),這一點(diǎn)很重要,很多開(kāi)發(fā)同學(xué)都忘了這一步)
  • 第七步,使用線程池異步發(fā)送驗(yàn)證碼郵件

圖片圖片

前端在調(diào)用完 /sendEmailCode 接口后,就可以拿到 emailKey。

這樣等用戶輸入郵箱里的驗(yàn)證碼后,點(diǎn)擊注冊(cè)按鈕,我們就可能正式開(kāi)始注冊(cè)操作了。

/registry 用戶注冊(cè)

@PostMapping("/registry")
public R registry(@RequestBody RegistryObj registryObj) {
    // 驗(yàn)證兩次密碼輸入是否一致
    if (!StringUtils.equalsIgnoreCase(registryObj.getPassword(), registryObj.getConfirmPassword())) {
        return R.error(USER_TWO_PASSWORD_NOT_SAME_ERROR);
    }
    // 驗(yàn)證用戶手機(jī)號(hào)是否唯一
    long count = iMemberService.count(Wrappers.lambdaQuery(Member.class).eq(Member::getMobile, registryObj.getMobile()));
    if (count > 0) {
        return R.error(USER_PHONE_HAS_REGISTER_ERROR);
    }

    // 判斷圖形驗(yàn)證碼
    String redisCaptchaCode = redisCache.getCacheObject(registryObj.getCaptchaKey());
    if (registryObj.getCaptchaCode() == null || !redisCaptchaCode.equals(registryObj.getCaptchaCode().trim().toLowerCase())) {
        return R.error(USER_CAPTCHA_CODE_ERROR);
    }

    // 判斷郵箱驗(yàn)證碼
    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];
    // 判斷發(fā)送郵箱驗(yàn)證碼的手機(jī)號(hào)是否與用戶當(dāng)前傳入手機(jī)號(hào)一致
    if (!StringUtils.equalsIgnoreCase(mobile, registryObj.getMobile())) {
        return R.error(ReturnCodeEnum.USER_REGISTER_MOBILE_ERROR);
    }
    // 判斷用戶輸入郵箱驗(yàn)證碼是否正確
    if (registryObj.getEmailCode() == null || !redisEmailCode.equals(registryObj.getEmailCode().trim().toLowerCase())) {
        return R.error(ReturnCodeEnum.USER_EMAIL_CODE_ERROR);
    }
    // 刪除驗(yàn)證碼
    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));
}

注冊(cè)接口,需要邏輯完善,所以這里的校驗(yàn)邏輯會(huì)比較多,因?yàn)橐粋€(gè)商城最重要的幾個(gè)接口就是注冊(cè)、登錄、下單、支付等。

除了能讓用戶正常注冊(cè)外,有時(shí)候還需要確保用戶一個(gè)手機(jī)號(hào)只能注冊(cè)一個(gè)賬號(hào),完成對(duì)用戶手機(jī)號(hào)在商城的唯一性保障。除了先查詢用戶手機(jī)號(hào)是否已存在外,還需要對(duì)用戶 member 表的手機(jī)號(hào)字段設(shè)置唯一索引來(lái)完成。注冊(cè)接口講解如下,

唯一索引可以防止用戶重復(fù)點(diǎn)擊注冊(cè)按鈕,保證一個(gè)手機(jī)號(hào)只能注冊(cè)一個(gè)用戶。

  • 第一步,驗(yàn)證用戶輸入兩次密碼是否一致
  • 第二步,驗(yàn)證用戶輸入的手機(jī)號(hào)是否唯一
  • 第三步,驗(yàn)證用戶輸入的圖形驗(yàn)證碼是否于 Redis 中存儲(chǔ)一致
  • 第四步,驗(yàn)證發(fā)送郵箱驗(yàn)證碼的手機(jī)號(hào)是否于 Redis 中存儲(chǔ)一致
  • 第五步,驗(yàn)證用戶輸入的郵箱驗(yàn)證碼是否于 Redis 中存儲(chǔ)一致
  • 第六步,校驗(yàn)通過(guò),開(kāi)始刪除圖形驗(yàn)證碼、郵箱驗(yàn)證碼
  • 第七步,啟動(dòng)線程池,異步進(jìn)行用戶保存操作

圖片 圖片

責(zé)任編輯:武曉燕 來(lái)源: waynblog
相關(guān)推薦

2024-12-03 09:45:34

2020-11-16 13:38:31

PostMessage

2016-12-28 14:51:46

大數(shù)據(jù)應(yīng)用

2021-07-28 06:10:47

拖拽設(shè)計(jì)器 transmat

2021-09-05 07:55:37

前端Emoji 表情

2015-04-16 09:48:12

APP測(cè)試

2015-09-22 16:01:08

平安WiFi

2024-08-02 08:38:20

Controller接口地址

2013-08-22 10:28:50

.NET MVC.NETRazor

2009-04-21 10:19:24

Oracle智慧的地球IBM

2018-01-08 07:34:39

比特幣數(shù)字貨幣央行

2019-01-29 10:00:59

GitHub開(kāi)源搜索

2024-06-13 08:19:08

Controller接口參數(shù)

2024-01-30 09:21:29

CSS文字效果文字裝飾

2022-05-25 08:42:32

sentinel流控規(guī)則

2018-12-12 11:30:54

JavaString字符串

2024-05-17 09:37:26

format屬性Spring

2021-04-09 08:23:30

Css前端加載動(dòng)畫(huà)

2012-10-24 13:36:50

1億部 iPad跌幅 3.26%

2012-03-24 20:31:59

移動(dòng)游戲
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)