最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot基于redis實現(xiàn)登錄校驗的示例

 更新時間:2026年03月10日 09:38:57   作者:漫霂  
本文介紹SpringBoot項目基于手機驗證碼的登錄實現(xiàn),包括驗證碼發(fā)送、Redis存儲、用戶登錄與創(chuàng)建、攔截器校驗Token及ThreadLocal數(shù)據(jù)共享,需要的朋友們下面隨著小編來一起學習學習吧

實現(xiàn)流程

  1. 發(fā)送短信驗證碼,并將驗證碼保存在redis。

  2. 根據(jù)用戶登錄數(shù)據(jù)完成登錄。

    1. 如果是新用戶還要創(chuàng)建用戶。
    2. 如果查詢到則轉化為DTO保存。
      將用戶數(shù)據(jù)被保存到redis,并將token保存到redis,同時返回給前端。
  3. 創(chuàng)建登錄校驗攔截器。
    注冊登錄校驗攔截器。

發(fā)送驗證碼接口

請求參數(shù):手機號phone
無結果對象

service層實現(xiàn)

@Override  
public Result sendCode(String phone) {  
    //1.校驗手機號  
    if (RegexUtils.isPhoneInvalid(phone)) {  
        return Result.fail("手機號格式錯誤!");  
    }  
    //2.生成驗證碼  
    String code = RandomUtil.randomNumbers(6);  
    //3.將驗證碼保存在redis  
    stringRedisTemplate.opsForValue().set(LOGIN_CODE_KEY + phone, code, LOGIN_CODE_TTL, TimeUnit.MINUTES);  
    //4.模擬發(fā)送驗證碼  
    log.debug("發(fā)送短信驗證碼成功,驗證碼:{}", code);  
    return Result.ok();  
}

接口介紹

  1. 根據(jù)正則表達式檢驗手機號格式。
  2. 通過hutool生成6位隨機數(shù)作為驗證碼。
  3. 將驗證碼保存在redis中。
  4. 將驗證碼發(fā)送給客戶端(此處應使用相關云服務完成,筆者使用日志只為記錄數(shù)據(jù))。

登錄接口

請求參數(shù):已經(jīng)封裝好的LoginFormDTO對象
結果對象:token

service層實現(xiàn)

@Override  
public Result login(LoginFormDTO loginForm) {  
    //1.校驗手機號格式  
    String phone = loginForm.getPhone();  
    if (RegexUtils.isPhoneInvalid(phone)) {  
        return Result.fail("手機號格式錯誤!");  
    }  
    //2.校驗驗證碼  
    String cacheCode = stringRedisTemplate.opsForValue().get(LOGIN_CODE_KEY + phone);  
    String code = loginForm.getCode();  
    if (cacheCode == null || !cacheCode.equals(code)) {  
        return Result.fail("驗證碼錯誤!");  
    }  
    //3.根據(jù)手機號查詢用戶  
    User user = query().eq("phone", phone).one();  
    //4.判斷用戶是否存在  
    if (user == null) {  
        //5.沒有用戶則創(chuàng)建新用戶  
        user = createUserWithPhone(phone);  
    }  
    //6.保存用戶信息到redis,(以哈希儲存)  
        //1.通過UUID拼裝tokenKey  
    String token = UUID.randomUUID().toString(true);  
    String tokenKey = LOGIN_USER_KEY + token;  
        //2.將UserDTO對象轉為HashMap存儲, 由于使用的是stringRedisTemplate,要保證所有的值都是字符串類型,要把lang轉換為string  
    UserDTO userDTO = BeanUtil.copyProperties(user, UserDTO.class);  
  
    Map<String, Object> userMap = BeanUtil.beanToMap(userDTO, new HashMap<>(),  
            CopyOptions  
                    .create()//創(chuàng)建默認數(shù)據(jù)拷貝選項  
                    .setIgnoreNullValue(true) //忽略null值  
                    /*字段值修改器,接收實現(xiàn)修改的方法*/  
                    .setFieldValueEditor(  
                            (fieldName, fieldValue) -> fieldValue.toString()  
                    )  
            );  
  
    stringRedisTemplate.opsForHash().putAll(tokenKey, userMap);  
        //3.設置token的有效期  
    stringRedisTemplate.expire(tokenKey, LOGIN_USER_TTL, TimeUnit.SECONDS);  
    //7.返回token  
    return Result.ok(tokenKey);  
}

接口介紹

  1. 校驗手機號格式。
  2. 校驗驗證碼。
  3. 根據(jù)手機號查詢用戶信息(使用MybatisPlus)。
  4. 通過UUID生成隨機token,所為key,將查詢后得到的UserDTO(將User轉換為UserDTO,避免暴漏敏感數(shù)據(jù)),封裝為hash(使用hutool相關API),存入redis,并設置有效期。
  5. 返回token。

手動創(chuàng)建攔截器

在實現(xiàn)了HandlerInterceptor的類中重寫preHandle和afterCompletion來實現(xiàn)對每一次請求的處理。

public class LoginInInterceptor implements HandlerInterceptor {  
  
    private StringRedisTemplate stringRedisTemplate;  
  
    public LoginInInterceptor(StringRedisTemplate stringRedisTemplate) {  
        this.stringRedisTemplate = stringRedisTemplate;  
    }  
      
    @Override  
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {  
  
        //獲取請求頭中的token  
        String token = request.getHeader("authorization");  
        if (token == null) {  
            response.setStatus(401);  
            return false;  
        }  
        //根據(jù)token從redis中獲取用戶信息  
        String key = LOGIN_USER_KEY + token;  
        Map<Object, Object> userMap = stringRedisTemplate.opsForHash().entries(key);  
        if (userMap.isEmpty()) {  
            response.setStatus(401);  
            return false;  
        }  
  
        //將map轉換為UserDTO對象  
        UserDTO userDTO = BeanUtil.fillBeanWithMap(userMap, new UserDTO(), false);  
  
        //保存用戶信息到ThreadLocal  
        UserHolder.saveUser(userDTO);  
        //刷新token有效期  
        stringRedisTemplate.expire(key, LOGIN_USER_TTL, TimeUnit.SECONDS);  
        return true;  
    }  
      
    @Override  
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {  
        UserHolder.removeUser();  
    }  
}

用前注意:
該自定義攔截器未交給Spring容器管理,不能使用@Autowired或者@Resource自動注入依賴,此處使用構造器注入stringRedisTemplate。

執(zhí)行邏輯:
preHandle執(zhí)行攔截校驗

  1. getHeader獲取請求頭中的token,并進行非空判斷。
  2. 根據(jù)token從redis中獲取userMap,再次使用hutool包的API將map集合轉換為實體類。
  3. 使用工具類將userDTO保存到ThreadLocal,實現(xiàn)跨層級數(shù)據(jù)共享。
  4. 刷新token有效期,提升用戶體驗。
    afterCompletion執(zhí)行清理ThreadLocal
    請求完成后清理ThreadLocal中的數(shù)據(jù),防止內存泄漏和數(shù)據(jù)污染。

注冊攔截器

在含有@Configuration 且實現(xiàn)了WebMvcConfigurer 的配置類中添加自定義攔截器

@Configuration  
public class MvcConfig implements WebMvcConfigurer {  
  
    @Resource  
    private StringRedisTemplate stringRedisTemplate;  
  
    @Override  
    public void addInterceptors(InterceptorRegistry registry) {  
        registry.addInterceptor(new LoginInInterceptor(stringRedisTemplate))  
                .excludePathPatterns(  
                        "/user/code",  
                        "/user/login",  
                        "/blog/hot",  
                        "/shop/**",  
                        "/shop-type/**",  
                        "/voucher/**",  
                        "/upload/**"  
                );  
    }  
}

執(zhí)行邏輯:

  1. 使用@Resource注解注入stringRedisTemplate
  2. 重寫addInterceptors方法
  3. 調用registry的addInterceptor方法添加攔截器(形參中new出LoginInInterceptor,并將正確注入的stringRedisTemplate傳遞給LoginInInterceptor,完成自定義攔截器中的依賴注入)。
  4. 調用excludePathPatterns指明不攔截的請求

攔截器的優(yōu)化

由于將校驗登錄狀態(tài)和刷新token有效期合并在了一個攔截器中,所以在用戶訪問一些不攔截登錄的接口時無法刷新token有效期,為此,我們將它拆分為兩個攔截器

刷新攔截器:

只為刷新token有效期

  • 如果無token直接放行讓用戶進行登錄
  • 如果有token則將用戶保存在ThreadLoacl(便于攔截登錄)并刷新token有效期
public class ReFreshTokenInterceptor implements HandlerInterceptor {  
  
    private StringRedisTemplate stringRedisTemplate;  
  
    public ReFreshTokenInterceptor(StringRedisTemplate stringRedisTemplate) {  
        this.stringRedisTemplate = stringRedisTemplate;  
    }  
  
    @Override  
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {  
  
        //獲取請求頭中的token  
        String token = request.getHeader("authorization");  
        if (token == null) {  
            return true;  
        }  
        //根據(jù)token從redis中獲取用戶信息  
        String key = token;  
        Map<Object, Object> userMap = stringRedisTemplate.opsForHash().entries(key);  
        if (userMap.isEmpty()) {  
            return true;  
        }  
  
        //將map轉換為UserDTO對象  
        UserDTO userDTO = BeanUtil.fillBeanWithMap(userMap, new UserDTO(), false);  
  
        //保存用戶信息到ThreadLocal  
        UserHolder.saveUser(userDTO);  
        //刷新token有效期  
        stringRedisTemplate.expire(key, LOGIN_USER_TTL, TimeUnit.SECONDS);  
        return true;  
    }  
  
    @Override  
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {  
        UserHolder.removeUser();  
    }  
}

登錄攔截器:

只為攔截未登錄用戶

public class LoginInInterceptor implements HandlerInterceptor {  
  
    @Override  
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {  
        //判斷是否需要攔截(ThreadLocal中是否有用戶)  
        if (UserHolder.getUser() == null) {  
            //無用戶,進行攔截  
            response.setStatus(401);  
            return false;  
        }  
        //有用戶,放行  
        return true;  
    }  
  
    @Override  
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {  
        UserHolder.removeUser();  
    }  
  
}

配置攔截順序

@Configuration  
public class MvcConfig implements WebMvcConfigurer {  
  
    @Resource  
    private StringRedisTemplate stringRedisTemplate;  
  
    @Override  
    public void addInterceptors(InterceptorRegistry registry) {  
        registry.addInterceptor(new LoginInInterceptor())  
                .excludePathPatterns(  
                        "/user/code",  
                        "/user/login",  
                        "/blog/hot",  
                        "/shop/**",  
                        "/shop-type/**",  
                        "/voucher/**",  
                        "/upload/**"  
                ).order(1);  
            registry.addInterceptor(new ReFreshTokenInterceptor(stringRedisTemplate)).order(0);  
    }  
}

order值低的優(yōu)先進行攔截

到此這篇關于SpringBoot基于redis實現(xiàn)登錄校驗的示例的文章就介紹到這了,更多相關SpringBoot redis登錄校驗內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • 淺談JAVA 內存流的實現(xiàn)

    淺談JAVA 內存流的實現(xiàn)

    這篇文章主要介紹了淺談JAVA 內存流的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-02-02
  • Java編程接口回調一般用法代碼解析

    Java編程接口回調一般用法代碼解析

    本文的主要內容是同過實際代碼向大家展示Java編程中接口回調的一般用法,具有一定參考價值,需要的朋友可以了解下
    2017-09-09
  • java面試常見問題之Hibernate總結

    java面試常見問題之Hibernate總結

    這篇文章主要介紹了在java面試過程中hibernate比較常見的問題,包括Hibernate的檢索方式,Hibernate中對象的狀態(tài),Hibernate的3種檢索策略是什么,Session的find()方法以及Query接口的區(qū)別等方面問題的總結,需要的朋友可以參考下
    2015-07-07
  • java實現(xiàn)數(shù)字轉大寫的方法

    java實現(xiàn)數(shù)字轉大寫的方法

    這篇文章主要介紹了 java實現(xiàn)數(shù)字轉大寫的方法的相關資料,希望通過本文能幫助到大家,讓大家實現(xiàn)這樣的功能,需要的朋友可以參考下
    2017-10-10
  • Java如何將String轉換成json對象或json數(shù)組

    Java如何將String轉換成json對象或json數(shù)組

    這篇文章主要介紹了Java如何將String轉換成json對象或json數(shù)組,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-02-02
  • Intellij?IDEA創(chuàng)建web項目的超詳細步驟記錄

    Intellij?IDEA創(chuàng)建web項目的超詳細步驟記錄

    如果剛開始接觸IDEA,或者之前使用的是eclipse/myEclipse的話,即使是創(chuàng)建一個JAVA WEB項目,估計也讓很多人費了好幾個小時,下面這篇文章主要給大家介紹了關于Intellij?IDEA創(chuàng)建web項目的超詳細步驟,需要的朋友可以參考下
    2022-08-08
  • 淺析java消息摘要與數(shù)字簽名

    淺析java消息摘要與數(shù)字簽名

    這篇文章給大家分析了關于java消息摘要與數(shù)字簽名的相關知識點內容,有興趣的朋友們可以學習下。
    2018-08-08
  • ElasticSearch學習之Es集群Api操作示例

    ElasticSearch學習之Es集群Api操作示例

    這篇文章主要為大家介紹了ElasticSearch學習之Es集群Api操作示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-01-01
  • tomcat報錯:Wrapper cannot find servlet class ...問題解決

    tomcat報錯:Wrapper cannot find servlet class ...問題解決

    這篇文章主要介紹了tomcat報錯:Wrapper cannot find servlet class ...問題解決的相關資料,需要的朋友可以參考下
    2016-11-11
  • 注入jar包里的對象,用@autowired的實例

    注入jar包里的對象,用@autowired的實例

    這篇文章主要介紹了注入jar包里的對象,用@autowired的實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-09-09

最新評論

平阴县| 天柱县| 溆浦县| 商南县| 正宁县| 莱芜市| 石狮市| 信阳市| 濮阳县| 梅河口市| 宁阳县| 长葛市| 开化县| 望江县| 凉城县| 万山特区| 常宁市| 达拉特旗| 天津市| 桂平市| 台安县| 白河县| 巴中市| 兴和县| 饶平县| 偏关县| 犍为县| 和林格尔县| 江源县| 南溪县| 沁水县| 新蔡县| 同仁县| 临沂市| 尼玛县| 汶上县| 毕节市| 固镇县| 辰溪县| 莎车县| 调兵山市|