亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Redis進行驗證碼登錄的項目實踐

 更新時間:2025年09月07日 14:18:52   作者:雞蛋灌Bean  
本文主要介紹了Redis進行驗證碼登錄的項目實踐,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

1.基于Session進行對驗證碼等信息進行存儲

我們?nèi)绻獙崿F(xiàn)一個驗證碼的收發(fā)校驗登錄的模塊,可以基于Session來進行對信息的存儲,然后通過對這些信息的校驗來完成對驗證碼的校驗

首先要了解發(fā)送驗證碼的邏輯

注意:以下內(nèi)容所有帶Utill的類都是hutool包下的類,在使用時導(dǎo)入依賴即可使用

1.1發(fā)送驗證碼

流程如下:

在controller中定義方法,傳參為前端的手機號和session,其中session是儲存信息的容器,可以實現(xiàn)存儲用戶,手機號等信息

    @PostMapping("code")
    public Result sendCode(@RequestParam("phone") String phone, HttpSession session) {
        //發(fā)送短信驗證碼并保存驗證碼
        return userService.sendCode(phone,session);
    }

在service里定義方法后在實現(xiàn)類中實現(xiàn)

根據(jù)流程來分步實現(xiàn),這里發(fā)送驗證碼的用到了Hutool包里的生成隨機數(shù)來生成驗證碼。

苒后利用一個Utils包里的lambda表達式來判斷手機號格式

 /**
     * 是否是無效手機格式
     * @param phone 要校驗的手機號
     * @return true:符合,false:不符合
     */
    public static boolean isPhoneInvalid(String phone){
        return mismatch(phone, RegexPatterns.PHONE_REGEX);
    }
    /**
 /**
     * 手機號正則
     */
    public static final String PHONE_REGEX = "^1([38][0-9]|4[579]|5[0-3,5-9]|6[6]|7[0135678]|9[89])\\d{8}$";

然后發(fā)送驗證碼可以利用阿里云來對手機號進行發(fā)送,但是我們主要講邏輯,就不實現(xiàn)這個功能了,直接用日志將驗證碼打印過來

 /**
     * 發(fā)送短信驗證碼
     * @return
     */
    @Override
    public Result sendCode(String phone, HttpSession session) {
        //1.校驗手機號

        if(RegexUtils.isPhoneInvalid(phone)){
            //不符合
            return Result.fail("手機號格式錯誤");
        }
        //符合
        //2.生成驗證碼
        String code = RandomUtil.randomNumbers(6);
        //3.保存驗證碼到seesion
        session.setAttribute("code",code);
        //4.發(fā)送驗證碼
        log.debug("發(fā)送成功,驗證碼為:{}", code);


        return Result.ok();
    }

苒后利用session來儲存驗證碼

1.2校驗驗證碼并登錄

流程如下:

 校驗驗證碼邏輯較為復(fù)雜,首先要定義方法

其中l(wèi)oginFormDTO里傳入的就是前端的參數(shù),如手機號,驗證碼等信息

    /**
     * 登錄功能
     * @param loginForm 登錄參數(shù),包含手機號、驗證碼;或者手機號、密碼
     */
    @PostMapping("/login")
    public Result login(@RequestBody LoginFormDTO loginForm, HttpSession session){
        //實現(xiàn)登錄功能
        return userService.login(loginForm,session);
    }

然后在實現(xiàn)類里實現(xiàn)

其中我們先將手機號從loginForm里取出來再進行判斷

@Override
    public Result login(LoginFormDTO loginForm, HttpSession session) {
        //1.校驗手機號
        String phone = loginForm.getPhone();
        if(RegexUtils.isPhoneInvalid(phone)){
            //不一致
            return Result.fail("手機號格式錯誤");
        }
        //一致
        //2.校驗驗證碼
        //先在session中取出驗證碼
        Object cacheCode = session.getAttribute("code");
        String code = loginForm.getCode();//前端提交的code
        //不一致
        if(cacheCode==null || !cacheCode.toString().equals(code)){
            return Result.fail("驗證碼已過期或錯誤");
        }
            //重新提交驗證碼
        //一致
        //3.根據(jù)手機號查詢用戶
        User user = query().eq("phone",phone).one();
        //用戶不存在
        if(user==null){
            //創(chuàng)建新用戶并保存到數(shù)據(jù)庫
            user =  creatUserWithPhone(phone);
            //保存用戶到session 在最后一步完成
        }

        //用戶存在
        //保存用戶到session
        //將user轉(zhuǎn)為dto儲存
        session.setAttribute("user", BeanUtil.copyProperties(user, UserDTO.class));

        return Result.ok();
    }

我們將驗證碼從session里取出來和前端得到的驗證碼進行對比:cacheCode對比code

再后利用mybatisplus進行查詢用戶存入到user中

然后判斷用戶是否存在,如果不存在,就證明是新用戶

新用戶創(chuàng)建我們利用一個方法creatUserWithPhone來根據(jù)手機號來進行創(chuàng)建

private User creatUserWithPhone(String phone) {

        //1.創(chuàng)建用戶
        //由于新用戶大部分創(chuàng)建時都有默認參數(shù),因此我們只需要將手機號和昵稱傳入即可,昵稱隨機
        //邏輯和大部分創(chuàng)建新用戶的軟件邏輯一樣
        User user = new User();
        user.setPhone(phone);
        user.setNickName(USER_NICK_NAME_PREFIX + RandomUtil.randomString(10));

        //2.保存到數(shù)據(jù)庫
        save(user);
        return null;
    }

 創(chuàng)建以后用mp存入到數(shù)據(jù)庫中

如果存在就將其轉(zhuǎn)為dto存入到session中以便后續(xù)使用

1.3攔截校驗

實現(xiàn)了基本邏輯業(yè)務(wù)后,就可以實現(xiàn)進行攔截校驗了

先寫一個攔截器,基本業(yè)務(wù)是:在每次請求處理之前獲取session里的用戶,如果用戶不存在,也就是在之前的登錄中沒有登錄,即沒有存入用戶信息,就進行攔截,返回401

然后在請求處理之后移除用戶信息,節(jié)約內(nèi)存開銷

//校驗登錄狀態(tài)
public class LoginInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //首先由于請求里面帶有cookie,我們的request參數(shù)例就有session,我們只需要在里面取出即可

        //1.獲取session
        HttpSession session = request.getSession();


        //2.獲取session中的用戶
        Object user = session.getAttribute("user");
        //3.判斷用戶是否存在
        if(user== null){
            //不存在,攔截,返回false即可攔截,返回401狀態(tài)碼
            response.setStatus(401);
            return false;
        }

        //存在,將用戶保存到ThreadLocal中
        UserHolder.saveUser((UserDTO) user);
        //放行
        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
       //移除用戶
        UserHolder.removeUser();
    }
}

然后在配置類里注冊這個攔截器

@Configuration
public class MvcConfig implements WebMvcConfigurer {

    //配置攔截器
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
       registry.addInterceptor(new LoginInterceptor())
               .excludePathPatterns(
                //排除一些路徑,不需要攔截的地方
                       //如一些頁面可以不需要登錄校驗
                       "/user/code",
                       "/user/login",
                       "/blog/hot",//查看熱點,也與登錄無關(guān),可以放行
                       "/shop/**",
                       "/shop-type/**",
                       "/upload/**",
                       "/voucher/**"

               );
    }

2.用Redis實現(xiàn)對驗證碼信息校驗

我們前面使用Httpsession來進行儲存用戶信息和驗證碼,但是使用session也有很多問題

主要是session的共享問題:

如果我們使用了tomcat集群來部署項目,多臺Tomcat并不共享session存儲空間,當請求切換到不同的tomcat服務(wù)時導(dǎo)致數(shù)據(jù)丟失的問題;

而session的替代方案應(yīng)該滿足:

1.數(shù)據(jù)共享

2.內(nèi)存存儲

3.key,value架構(gòu)

首先保存的基本思想是用手機號作為key來存儲,因為要保證每個用戶的key都不同

我們一般用String結(jié)構(gòu),以Json字符串來保存

或者使用hash結(jié)構(gòu)來進行保存,利用hash結(jié)構(gòu)將對象中的每個字段獨立儲存,可以針對單個字段進行CRUD,并且內(nèi)存占用更少

我們以hash結(jié)構(gòu)為例
我們只需要在原來的儲存session步驟上替換為存儲到Redis里即可

邏輯如下:

注意:

但是在校驗驗證碼登錄注冊時,我們儲存用戶信息的key可以使用隨機生成的token,值為json對象,為了防止泄漏風險,然后判斷用戶是否存在時如果存在,就報錯用戶到Redis里,然后返回token給前端,不存在也在創(chuàng)建新用戶后返回token給前端

而且session仍然有用,就是在request請求頭中的token里的session就存儲的有用戶信息,作為校驗登錄狀態(tài)時判斷用戶是否存在的依據(jù),就是在登錄或者注冊后得到的token獲取用戶信息

2.1發(fā)送驗證碼時存儲到Redis邏輯

我們之前已經(jīng)實現(xiàn)了發(fā)送驗證碼的功能,我們只需要修改存儲驗證碼到session這個功能即可

在pom文檔里導(dǎo)入Redis客戶端依賴:

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

首先導(dǎo)入RedisTemplete實現(xiàn)API,這里用@Resource和@Autowired進行注入都可以

一個是針對類名裝配,一個針對類型裝配

    @Resource
    private StringRedisTemplate stringRedisTemplate;

然后修改業(yè)務(wù)邏輯

        //3.保存驗證碼到seesion
//        session.setAttribute("code",code);
        //在key里加上一個前綴來和其他業(yè)務(wù)里的phone來區(qū)分
        //然后設(shè)置一個有效期
        stringRedisTemplate.opsForValue().set("login:code:"+phone,code,2, TimeUnit.MINUTES);

2.2校驗驗證碼實現(xiàn)登錄注冊邏輯

首先就是修改從session中獲取驗證碼進行校驗的邏輯

 //從Redis獲取驗證碼并校驗
        String cacheCode = stringRedisTemplate.opsForValue().get(LOGIN_CODE_KEY+phone);
        String code = loginForm.getCode();//前端提交的code

然后就是修改保存用戶信息到redis中這些邏輯

我們把用戶信息設(shè)置為哈希類型,把號碼設(shè)置為string類型,因為哈希類型可以保證用戶信息等隱私

        //保存用戶到Redis中

        //3.1生成token作為登錄令牌
        String token = UUID.randomUUID().toString(true);
        //3.2將USer對象轉(zhuǎn)為HashMap存儲
        UserDTO userDTO= BeanUtil.copyProperties(user,UserDTO.class);
        Map<String,Object> userMap= BeanUtil.beanToMap(userDTO);
        //3.3存儲,利用putALL,key可以是多個值,即hashMap,然后設(shè)置有效期
        String tokenKey= LOGIN_CODE_KEY+token;
        stringRedisTemplate.opsForHash().putAll(tokenKey,userMap);
        //設(shè)置有效期
        stringRedisTemplate.expire(tokenKey,LOGIN_USER_TTL,TimeUnit.MINUTES);
        //但是還有一個問題,就是有效期的邏輯是,只要是在有效期內(nèi)無論進行訪問,只要有效期到了就失效,不會重置有效期
        //因此我們要進行修改邏輯,修改為,只要三十分鐘內(nèi)訪問過了就重置有效期,又可以過三十分鐘過期

        //我們就可以利用攔截器來實現(xiàn),只要訪問了請求,即觸發(fā)了攔截器,就實現(xiàn)更新有效期的操作
        //8.返回token給前端
        return Result.ok();

然后修改校驗登錄狀態(tài)時的從redis獲取用戶邏輯

如圖,然后在每次校驗時也要刷新token有效期

//1.獲取請求頭中的token,根據(jù)前端返回的名字來獲取
        String token= request.getHeader("authorization");
        if(StrUtil.isBlank(token)){
            response.setStatus(401);
            return false;
        }


        //2.基于token獲取redis中的用戶,利用entries來獲取所有key里的值組成hashMap
       Map<Object,Object> userMap= stringRedisTemplate.opsForHash().entries(RedisConstants.LOCK_SHOP_KEY+token);
        //3.判斷用戶是否存在
        if(userMap.isEmpty()){
            //不存在,攔截,返回false即可攔截,返回401狀態(tài)碼
            response.setStatus(401);
            return false;
        }
        //將查詢到的hash轉(zhuǎn)為userDto對象
       UserDTO userDTO= BeanUtil.fillBeanWithMap(userMap,new UserDTO(),false);
        //存在,將用戶保存到ThreadLocal中
        UserHolder.saveUser(userDTO);

        //刷新token有效期
        stringRedisTemplate.expire(RedisConstants.LOCK_SHOP_KEY+token,30, TimeUnit.MINUTES);
        //放行
        return true;

到此這篇關(guān)于Redis進行驗證碼登錄的項目實踐的文章就介紹到這了,更多相關(guān)Redis 驗證碼登錄內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Redis動態(tài)熱點數(shù)據(jù)緩存策略設(shè)計

    Redis動態(tài)熱點數(shù)據(jù)緩存策略設(shè)計

    本文主要介紹了Redis動態(tài)熱點數(shù)據(jù)緩存策略設(shè)計,包括熱點數(shù)據(jù)識別、動態(tài)緩存、多級緩存、預(yù)加載機制、更新策略以及監(jiān)控告警等,具有一定的參考價值,感興趣的可以了解一下
    2025-01-01
  • Spring?Boot?緩存?與?Redis問題小結(jié)

    Spring?Boot?緩存?與?Redis問題小結(jié)

    本文總結(jié)SpringBoot緩存方案,對比Redis與EnCache優(yōu)劣,指出Redis支持集群但效率較低,EnCache速度快但不支持分布式,SpringBoot默認使用ConcurrentHashMapManager,本文給大家介紹Spring?Boot緩存與Redis問題小結(jié),感興趣的朋友一起看看吧
    2025-07-07
  • Redis過期Key刪除策略和內(nèi)存淘汰策略的實現(xiàn)

    Redis過期Key刪除策略和內(nèi)存淘汰策略的實現(xiàn)

    當內(nèi)存使用達到上限,就無法存儲更多數(shù)據(jù)了,為了解決這個問題,Redis內(nèi)部會有兩套內(nèi)存回收的策略,過期Key刪除策略和內(nèi)存淘汰策略,本文就來詳細的介紹一下這兩種方法,感興趣的可以了解一下
    2024-02-02
  • Redis的五種基本類型和業(yè)務(wù)場景和使用方式

    Redis的五種基本類型和業(yè)務(wù)場景和使用方式

    Redis是一種高性能的鍵值存儲數(shù)據(jù)庫,支持多種數(shù)據(jù)結(jié)構(gòu)如字符串、列表、集合、哈希表和有序集合等,它提供豐富的API和持久化功能,適用于緩存、消息隊列、排行榜等多種場景,Redis能夠?qū)崿F(xiàn)高速讀寫操作,尤其適合需要快速響應(yīng)的應(yīng)用
    2024-10-10
  • kubernetes環(huán)境部署單節(jié)點redis數(shù)據(jù)庫的方法

    kubernetes環(huán)境部署單節(jié)點redis數(shù)據(jù)庫的方法

    這篇文章主要介紹了kubernetes環(huán)境部署單節(jié)點redis數(shù)據(jù)庫的方法,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-01-01
  • Redis 實現(xiàn)隊列原理的實例詳解

    Redis 實現(xiàn)隊列原理的實例詳解

    這篇文章主要介紹了Redis 實現(xiàn)隊列原理的實例詳解的相關(guān)資料,希望通過本文能幫助到大家,需要的朋友可以參考下
    2017-09-09
  • redis持久化AOF和RDB的區(qū)別及解決各個場景問題示例

    redis持久化AOF和RDB的區(qū)別及解決各個場景問題示例

    這篇文章主要為大家介紹了redis持久化AOF和RDB的區(qū)別及解決各個場景問題示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-08-08
  • Redis在windows環(huán)境下如何啟動

    Redis在windows環(huán)境下如何啟動

    這篇文章主要介紹了Redis在windows環(huán)境下如何啟動的實現(xiàn)方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2025-04-04
  • Redis隊列和阻塞隊列的實現(xiàn)

    Redis隊列和阻塞隊列的實現(xiàn)

    本文主要介紹了Redis隊列和阻塞隊列的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-11-11
  • Redis如何實現(xiàn)投票功能

    Redis如何實現(xiàn)投票功能

    這篇文章主要介紹了Redis如何實現(xiàn)投票功能,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-05-05

最新評論