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

SpringBoot實(shí)現(xiàn)賬號(hào)登錄錯(cuò)誤次數(shù)的限制和鎖定功能

 更新時(shí)間:2024年12月02日 11:11:40   作者:小小工匠  
本文介紹了如何使用SpringBoot和Redis實(shí)現(xiàn)賬號(hào)登錄錯(cuò)誤次數(shù)限制和鎖定功能,通過(guò)自定義注解和AOP切面,結(jié)合配置文件靈活設(shè)置最大嘗試次數(shù)和鎖定時(shí)長(zhǎng),感興趣的朋友跟隨小編一起看看吧

Pre

SpringBoot - 優(yōu)雅的實(shí)現(xiàn)【流控】

需求

需求描述:

  • 登錄錯(cuò)誤次數(shù)限制:在用戶(hù)登錄時(shí),記錄每個(gè)賬號(hào)的登錄錯(cuò)誤次數(shù),并限制連續(xù)錯(cuò)誤的次數(shù)。
  • 賬號(hào)鎖定機(jī)制:當(dāng)一個(gè)賬號(hào)連續(xù)輸入錯(cuò)誤密碼超過(guò)5次時(shí),該賬號(hào)將被鎖定15分鐘。在15分鐘后,賬號(hào)會(huì)自動(dòng)解鎖。
  • 自動(dòng)解鎖功能:賬號(hào)在連續(xù)錯(cuò)誤輸入超過(guò)5次后,將觸發(fā)鎖定機(jī)制,并且5分鐘后自動(dòng)解鎖,利用Redis的鍵值存儲(chǔ)來(lái)管理錯(cuò)誤次數(shù)和鎖定時(shí)間。
  • 配置文件:登錄錯(cuò)誤次數(shù)的限制(如5次錯(cuò)誤)和賬號(hào)鎖定時(shí)間(如15分鐘)應(yīng)該能通過(guò)配置文件進(jìn)行設(shè)置,以便靈活配置。
  • 自定義注解實(shí)現(xiàn):使用自定義注解來(lái)實(shí)現(xiàn)登錄錯(cuò)誤次數(shù)限制與賬號(hào)鎖定功能的邏輯。

技術(shù)細(xì)節(jié):

  • 使用Redis的Key來(lái)存儲(chǔ)和管理每個(gè)用戶(hù)的錯(cuò)誤登錄次數(shù)和鎖定狀態(tài)。
  • 自定義注解實(shí)現(xiàn)錯(cuò)誤次數(shù)和鎖定時(shí)長(zhǎng)的判斷與控制。
  • 錯(cuò)誤次數(shù)和鎖定時(shí)長(zhǎng)通過(guò)配置文件(如application.ymlapplication.properties)進(jìn)行配置,支持靈活調(diào)整。

實(shí)現(xiàn)步驟

簡(jiǎn)易實(shí)現(xiàn)

1. 添加依賴(lài)

首先,在pom.xml中添加必要的依賴(lài):

 <dependencies>
    <!-- Spring Boot Starter Data Redis -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    <!-- Spring Boot Starter Web -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- Spring Boot Starter AOP -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>
</dependencies>

2. 配置文件

在application.yml中配置相關(guān)參數(shù):

3. 自定義注解

創(chuàng)建一個(gè)自定義注解@LoginAttemptLimit:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface LoginAttemptLimit {
    // 默認(rèn)值依賴(lài)配置文件,可在此處設(shè)定默認(rèn)值
    int maxAttempts() default 5;
    int lockTime() default 15;
}

4. AOP切面

創(chuàng)建一個(gè)AOP切面來(lái)處理登錄錯(cuò)誤次數(shù)的限制和鎖定邏輯:

@Aspect
@Slf4j
@Component
public class LoginAttemptLimitAspect {
    @Resource
    private LoginAttemptValidator loginAttemptValidator;
    @Resource
    private AdminAuthService authService;
    @Value("${supervision.max-attempts:2}")
    private int maxAttempts;
    @Value("${supervision.lock-time:5}")
    private long lockTime;
    @Around("@annotation(loginAttemptLimit)")
    public Object limitLoginAttempts(ProceedingJoinPoint joinPoint, LoginAttemptLimit loginAttemptLimit) throws Throwable {
        String attemptKey = "";
        String lockKey = "";
        // 根據(jù)登錄類(lèi)型獲取對(duì)應(yīng)的鍵
        // # 0 賬號(hào)密碼模式  1 key模式(默認(rèn))
        if (authService.getLoginType() == 1) {
            AuthKeyLoginReqVO authKeyLoginReqVO = (AuthKeyLoginReqVO) joinPoint.getArgs()[0];
            attemptKey = RedisKeyConstants.ATTEMP_KEY_PREFIX + authKeyLoginReqVO.getUsername();
            lockKey = RedisKeyConstants.LOCK_KEY_PREFIX + authKeyLoginReqVO.getUsername();
        } else {
            AuthLoginReqVO authLoginReqVO = (AuthLoginReqVO) joinPoint.getArgs()[0];
            attemptKey = RedisKeyConstants.ATTEMP_KEY_PREFIX + authLoginReqVO.getUsername();
            lockKey = RedisKeyConstants.LOCK_KEY_PREFIX + authLoginReqVO.getUsername();
        }
        // 檢查賬號(hào)是否已被鎖定
        if (loginAttemptValidator.isLocked(lockKey)) {
            throw new ServiceException(TOO_MANY_REQUESTS.getCode(), "賬號(hào)被鎖定,請(qǐng)稍后重試");
        }
        // 獲取登錄次數(shù)
        int attempts = loginAttemptValidator.getAttempt(attemptKey);
        // 檢查登錄嘗試次數(shù)是否超過(guò)最大限制
        if (attempts >= maxAttempts) {
            loginAttemptValidator.setLock(lockKey, lockTime);
            loginAttemptValidator.resetAttempt(attemptKey);
            throw new ServiceException(TOO_MANY_REQUESTS.getCode(), "賬號(hào)被鎖定,請(qǐng)稍后重試");
        }
        try {
            // 執(zhí)行登錄操作
            Object result = joinPoint.proceed();
            // 登錄成功,重置登錄嘗試計(jì)數(shù)
            loginAttemptValidator.resetAttempt(attemptKey);
            return result;
        } catch (Exception e) {
            // 登錄失敗,增加登錄嘗試計(jì)數(shù)
            loginAttemptValidator.incrementAttempt(attemptKey);
            throw e;
        }
    }
}

5. 使用自定義注解:

在服務(wù)的方法上添加自定義注解

6. 測(cè)試

創(chuàng)建一個(gè)控制器來(lái)處理登錄請(qǐng)求

連續(xù)錯(cuò)誤5次后,

Redis中Key的TTL

import cn.hutool.core.util.ObjectUtil;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;
@Component
public class LoginAttemptValidator {
    @Resource
    private RedisTemplate<String,Integer> redisTemplate;
    /**
     * 嘗試次數(shù)自增
     *
     * @param key Redis中的鍵,用于標(biāo)識(shí)特定的嘗試計(jì)數(shù)
     */
    public void incrementAttempt(String key) {
        redisTemplate.opsForValue().increment(key);
    }
    /**
     * 獲取嘗試次數(shù)
     * 如果給定鍵的嘗試次數(shù)在緩存中不存在,則初始化嘗試次數(shù)為0
     * 此方法主要用于跟蹤某些操作的嘗試次數(shù),例如登錄嘗試次數(shù),以防止暴力破解
     *
     * @param key 緩存中的鍵,通常與特定用戶(hù)或操作相關(guān)聯(lián)
     * @return 嘗試次數(shù)如果緩存中沒(méi)有對(duì)應(yīng)的嘗試記錄,則返回0
     */
    public int getAttempt(String key) {
        // 從Redis中獲取嘗試次數(shù)
        Integer attempts = redisTemplate.opsForValue().get(key);
        // 如果嘗試次數(shù)為空,則初始化嘗試次數(shù)
        if (attempts == null ) initAttempt(key);
        // 返回嘗試次數(shù)如果為null,則返回0
        return attempts == null ? 0 : attempts;
    }
    /**
     * 初始化嘗試次數(shù)
     * 該方法用于在Redis中初始化一個(gè)鍵的嘗試次數(shù)為0
     * 主要用于記錄和管理操作的嘗試次數(shù),以便進(jìn)行后續(xù)的限制或監(jiān)控
     *
     * @param key Redis中的鍵,用于唯一標(biāo)識(shí)一個(gè)操作或請(qǐng)求
     */
    public void initAttempt(String key) {
        redisTemplate.opsForValue().set(key, 0);
    }
    /**
     * 重置嘗試次數(shù)
     * 通過(guò)刪除Redis中的鍵來(lái)重置特定嘗試的計(jì)數(shù)
     *
     * @param key Redis中用于標(biāo)識(shí)嘗試計(jì)數(shù)的鍵
     */
    public void resetAttempt(String key) {
        redisTemplate.delete(key);
    }
    /**
     * 設(shè)置緩存鎖
     *
     * @param key 鎖的唯一標(biāo)識(shí),通常使用業(yè)務(wù)鍵作為鎖的key
     * @param duration 鎖的持有時(shí)間,單位為分鐘
     *
     * 此方法旨在通過(guò)Redis實(shí)現(xiàn)分布式鎖的功能,通過(guò)設(shè)置一個(gè)具有過(guò)期時(shí)間的鍵值對(duì)來(lái)實(shí)現(xiàn)
     * 鍵值對(duì)的key為業(yè)務(wù)鍵,值為鎖定標(biāo)志,過(guò)期時(shí)間由參數(shù)duration指定
     */
    public void setLock(String key, long duration) {
        redisTemplate.opsForValue().set(key, RedisKeyConstants.LOCK_FLAG, duration, TimeUnit.MINUTES);
    }
    /**
     * 檢查給定鍵是否處于鎖定狀態(tài)
     *
     * @param key 要檢查的鍵
     * @return 如果鍵未鎖定,則返回false;如果鍵已鎖定,則返回true
     */
    public boolean isLocked(String key) {
        // 從Redis中獲取鍵對(duì)應(yīng)的值
        Integer value = redisTemplate.opsForValue().get(key);
        // 如果值為空,則表明鍵未鎖定,返回false
        if (ObjectUtil.isEmpty(value)) return  false ;
        // 比較鍵的值是否與鎖定標(biāo)志相等,如果相等則表明鍵已鎖定,返回true
        return RedisKeyConstants.LOCK_FLAG == redisTemplate.opsForValue().get(key);
    }
}

總結(jié)

基于Spring Boot的賬號(hào)登錄錯(cuò)誤次數(shù)限制和鎖定功能,使用了Redis來(lái)存儲(chǔ)登錄失敗次數(shù)和鎖定狀態(tài),并通過(guò)自定義注解和AOP來(lái)實(shí)現(xiàn)切面邏輯。配置文件中可以靈活配置最大嘗試次數(shù)和鎖定時(shí)長(zhǎng)。

到此這篇關(guān)于SpringBoot實(shí)現(xiàn)賬號(hào)登錄錯(cuò)誤次數(shù)的限制和鎖定功能的文章就介紹到這了,更多相關(guān)SpringBoot賬號(hào)登錄錯(cuò)誤鎖定內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • SpringCloud中Gateway實(shí)現(xiàn)鑒權(quán)的方法

    SpringCloud中Gateway實(shí)現(xiàn)鑒權(quán)的方法

    本文主要介紹了SpringCloud中Gateway實(shí)現(xiàn)鑒權(quán)的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-11-11
  • springboot相關(guān)面試題匯總詳解

    springboot相關(guān)面試題匯總詳解

    這篇文章主要介紹了springboot相關(guān)面試題匯總詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-08-08
  • javaweb如何實(shí)現(xiàn)請(qǐng)求和響應(yīng)

    javaweb如何實(shí)現(xiàn)請(qǐng)求和響應(yīng)

    這篇文章主要為大家詳細(xì)介紹了javaweb如何實(shí)現(xiàn)請(qǐng)求和響應(yīng),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-10-10
  • SpringCloud項(xiàng)目集成Feign、Hystrix過(guò)程解析

    SpringCloud項(xiàng)目集成Feign、Hystrix過(guò)程解析

    這篇文章主要介紹了SpringCloud項(xiàng)目集成Feign、Hystrix過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-11-11
  • 通過(guò)端口1433連接到主機(jī)127.0.0.1的 TCP/IP 連接失敗,錯(cuò)誤:“connect timed out”的解決方法

    通過(guò)端口1433連接到主機(jī)127.0.0.1的 TCP/IP 連接失敗,錯(cuò)誤:“connect timed out”的解

    這篇文章主要介紹了通過(guò)端口1433連接到主機(jī)127.0.0.1的 TCP/IP 連接失敗,錯(cuò)誤:“connect timed out”的解決方法,需要的朋友可以參考下
    2015-08-08
  • springboot如何自定義pom內(nèi)子依賴(lài)版本

    springboot如何自定義pom內(nèi)子依賴(lài)版本

    這篇文章主要介紹了springboot如何自定義pom內(nèi)子依賴(lài)版本問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • Java一行代碼搞定耗時(shí)性能追蹤

    Java一行代碼搞定耗時(shí)性能追蹤

    在開(kāi)發(fā)過(guò)程中,性能監(jiān)控和調(diào)試是我們經(jīng)常面對(duì)的問(wèn)題,雖然市面上有許多成熟的性能監(jiān)控工具,但有時(shí)我們需要一個(gè)輕量級(jí)、靈活且優(yōu)雅的解決方案,下面我們就來(lái)看看Java如何搞定耗時(shí)性能追蹤吧
    2024-11-11
  • Java中StopWatch工具類(lèi)的用法詳解

    Java中StopWatch工具類(lèi)的用法詳解

    stopWatch 是org.springframework.util 包下的一個(gè)工具類(lèi),使用它可直觀的輸出代碼執(zhí)行耗時(shí),以及執(zhí)行時(shí)間百分比,下面就跟隨小編一起來(lái)看看它的具體用法吧
    2024-12-12
  • 帶你玩轉(zhuǎn)Kafka之初步使用

    帶你玩轉(zhuǎn)Kafka之初步使用

    最近開(kāi)發(fā)的項(xiàng)目中,kafka用的比較多,為了方便梳理,所以記錄一些關(guān)于kafka的文章,這篇文章主要給大家介紹了關(guān)于Kafka初步使用的相關(guān)資料,需要的朋友可以參考下
    2021-11-11
  • SpringBoot接口返回日期格式化的3種方法實(shí)現(xiàn)與對(duì)比

    SpringBoot接口返回日期格式化的3種方法實(shí)現(xiàn)與對(duì)比

    這篇文章主要為大家詳細(xì)介紹了SpringBoot中接口返回日期格式化的3種方法實(shí)現(xiàn)與對(duì)比,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2025-09-09

最新評(píng)論

仁寿县| 陆川县| 山丹县| 淮北市| 双柏县| 南开区| 仁怀市| 宁城县| 阜阳市| 新蔡县| 泸溪县| 岫岩| 西藏| 招远市| 垣曲县| 麟游县| 恭城| 连山| 孝义市| 西畴县| 峨眉山市| 台湾省| 上蔡县| 九寨沟县| 红河县| 旺苍县| 南召县| 天门市| 周宁县| 营山县| 修水县| 正定县| 琼海市| 岐山县| 晴隆县| 吐鲁番市| 浙江省| 仁布县| 衡阳县| 庄浪县| 东丽区|