欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Spring Security實現(xiàn)5次密碼錯誤觸發(fā)賬號自動鎖定功能

 更新時間:2024年12月23日 09:23:20   作者:后端小肥腸  
在現(xiàn)代互聯(lián)網(wǎng)應(yīng)用中,賬號安全是重中之重,然而,暴力 破解攻擊依然是最常見的安全威脅之一,攻擊者通過自動化腳本嘗試大量的用戶名和密碼組合,試圖找到漏洞進入系統(tǒng),所以為了解決這一問題,賬號鎖定機制被廣泛應(yīng)用,本文介紹了Spring Security實現(xiàn)5次密碼錯誤觸發(fā)賬號鎖定功能

1. 前言 

在現(xiàn)代互聯(lián)網(wǎng)應(yīng)用中,賬號安全是重中之重。然而,暴力 破解攻擊依然是最常見的安全威脅之一。攻擊者通過自動化腳本嘗試大量的用戶名和密碼組合,試圖找到漏洞進入系統(tǒng)。盡管我們可以通過復(fù)雜密碼要求、驗證碼、雙因子認證等方式來提高安全性,但這些方法無法完全杜絕暴力 破解的風險。

為了解決這一問題,賬號鎖定機制被廣泛應(yīng)用。通過限制用戶的密碼輸入錯誤次數(shù),當達到一定次數(shù)時鎖定賬號,可以有效防范暴力 破解攻擊,提高系統(tǒng)安全性。

以下是引入賬號鎖定機制的幾大原因:

  1. 防止暴力 破解攻擊:攻擊者短時間內(nèi)多次嘗試密碼時,鎖定機制能阻斷其進一步操作。
  2. 保護用戶資產(chǎn)和隱私:避免賬號被盜造成的財產(chǎn)損失和隱私泄露。
  3. 提升系統(tǒng)安全性:通過限制無效登錄嘗試次數(shù),降低因密碼弱點引發(fā)的安全隱患。
  4. 應(yīng)對安全合規(guī)要求:許多行業(yè)標準(如 GDPR、ISO27001)建議對異常登錄行為采取保護措施。

在本文中,我們將通過 Spring Security 來實現(xiàn)一個簡單而高效的賬號鎖定機制。當用戶密碼連續(xù)輸入錯誤達到 5 次后,系統(tǒng)將自動鎖定該賬號3分鐘。接下來,我們將通過技術(shù)流程、表結(jié)構(gòu)設(shè)計、核心代碼實現(xiàn)以及效果測試,詳細講解如何在 Spring Security 中落地這一功能。

2. 技術(shù)流程詳解

2.1.  技術(shù)流程講解

基于SpringSecurity實現(xiàn)密碼錯誤鎖定賬號的流程如下:

其實光看流程圖已經(jīng)能很清晰地理解完整流程,我這邊還是用文字再給大家梳理一遍:

1. 用戶提交登錄請求

用戶輸入用戶名和密碼后發(fā)起登錄請求,系統(tǒng)開始驗證其身份。

2. 加載用戶信息

Spring Security 使用自定義的 UserService 加載用戶信息,包括用戶名、密碼、鎖定狀態(tài)(accountNonLocked)、登錄失敗次數(shù)(loginAttempts)、鎖定時間(lockTime)等。

3. 檢查賬號鎖定狀態(tài)

  • 如果賬號被鎖定:
    • 判斷鎖定時間是否已過:
      • 鎖定時間未過:拋出 LockedException,阻止登錄。
      • 鎖定時間已過:解鎖賬號(accountNonLocked = true)、重置登錄失敗次數(shù)(loginAttempts = 0),并允許繼續(xù)登錄。
  • 如果賬號未鎖定,直接進入密碼驗證。

4. 驗證密碼

  • 密碼正確
    • 登錄成功,重置用戶狀態(tài)(失敗次數(shù)清零,鎖定狀態(tài)解除),并更新到數(shù)據(jù)庫。
  • 密碼錯誤
    • 增加登錄失敗次數(shù)(loginAttempts + 1)。
    • 如果失敗次數(shù)達到 5 次或以上,鎖定賬號(accountNonLocked = false),并記錄當前鎖定時間(lockTime = 當前時間)。

5. 更新用戶狀態(tài)

  • 登錄成功時:更新用戶信息到數(shù)據(jù)庫,并執(zhí)行登錄成功后的業(yè)務(wù)邏輯。
  • 登錄失敗時:更新用戶的失敗次數(shù)和鎖定狀態(tài)到數(shù)據(jù)庫,并執(zhí)行失敗后的處理邏輯。

6. 等待下次登錄嘗試

用戶根據(jù)賬號狀態(tài)和鎖定時間,決定何時再次發(fā)起登錄請求。

2.2. 涉及到的SpringSecurity核心組件

以上流程涉及到的SpringSecurity核心組件如下:

1. AuthenticationManager

  • 管理認證流程,調(diào)用 AuthenticationProvider 驗證用戶憑據(jù)。

2. AuthenticationProvider

  • 執(zhí)行具體的認證邏輯,包括密碼驗證和賬號狀態(tài)檢查。

3. PasswordEncoder

  • 用于密碼加密和驗證,例如使用 BCryptPasswordEncoder。

4. AuthenticationSuccessHandler

  • 處理登錄成功后的邏輯,例如重置失敗登錄次數(shù)和解鎖賬號。

5. AuthenticationFailureHandler

  • 處理登錄失敗后的邏輯,例如增加登錄失敗次數(shù)和鎖定賬號。

6. AuthenticationEntryPoint

  • 處理未認證用戶訪問受保護資源時的邏輯,返回錯誤信息。

7. SecurityContextHolder

  • 存儲和提供當前用戶的認證信息(Authentication 對象)。

8. ExceptionTranslationFilter

  • 捕獲認證過程中拋出的異常,并交給 AuthenticationEntryPoint 或 AuthenticationFailureHandler 處理。

9. UsernamePasswordAuthenticationFilter

  • 處理基于用戶名和密碼的登錄請求,觸發(fā)認證流程。

10.HttpSecurity

  • 配置認證流程和組件,包括認證、授權(quán)和異常處理。

這些組件共同協(xié)作,實現(xiàn) Spring Security 的認證和密碼錯誤鎖定賬號功能。

3. 技術(shù)實現(xiàn)

3.1. 表結(jié)構(gòu)設(shè)計

密碼錯誤賬號鎖定只涉及到user表,這是我的表結(jié)構(gòu),你可以根據(jù)你自己的靈活調(diào)整:

CREATE TABLE user (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(50) UNIQUE NOT NULL,
    password VARCHAR(255) NOT NULL,
    login_attempts INT DEFAULT 0, -- 登錄失敗次數(shù)
    lock_time TIMESTAMP NULL, -- 賬號鎖定時間
    account_non_locked BOOLEAN DEFAULT TRUE -- 賬號是否鎖定
);

3.2. 核心代碼

1. 編寫自定義UsernamePasswordAuthenticationFilter

public class SecurUsernamePasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
 
    @Autowired
    ISysUserService userService;
 
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request,
                                                HttpServletResponse response) throws AuthenticationException {
 
        if (request.getContentType().equals(MediaType.APPLICATION_JSON_UTF8_VALUE)
                || request.getContentType().equals(MediaType.APPLICATION_JSON_VALUE)) {
 
            ObjectMapper mapper = new ObjectMapper();
            UsernamePasswordAuthenticationToken authRequest = null;
            //取authenticationBean
            Map<String, String> authenticationBean = null;
            //用try with resource,方便自動釋放資源
            try (InputStream is = request.getInputStream()) {
                authenticationBean = mapper.readValue(is, Map.class);
            } catch (IOException e) {
                //將異常放到自定義的異常類中
                throw  new SecurAuthenticationException(e.getMessage());
            }
            try {
                if (!authenticationBean.isEmpty()) {
                    //獲得賬號、密碼
                    String username = authenticationBean.get(SPRING_SECURITY_FORM_USERNAME_KEY);
                    String password = authenticationBean.get(SPRING_SECURITY_FORM_PASSWORD_KEY);
 
                    request.setAttribute(SPRING_SECURITY_FORM_USERNAME_KEY, username);
 
                    //檢測賬號、密碼是否存在
                    if (userService.checkLogin(username, password)) {
                        //將賬號、密碼裝入UsernamePasswordAuthenticationToken中
                        authRequest = new UsernamePasswordAuthenticationToken(username, password);
                        setDetails(request,authRequest );
                        return this.getAuthenticationManager().authenticate(authRequest);
                    }
 
                }
            } catch (Exception e) {
                throw new SecurAuthenticationException(e.getMessage());
            }
            return null;
        } else {
            return this.attemptAuthentication(request, response);
        }
    }
}

這段代碼是一個自定義的 Spring Security 登錄過濾器,用于處理 JSON 格式的登錄請求(代替默認的表單登錄)。它通過解析請求體中的 JSON,提取用戶名和密碼,并調(diào)用用戶服務(wù)檢查登錄信息是否正確。如果驗證通過,則創(chuàng)建并返回一個 UsernamePasswordAuthenticationToken,交由認證管理器執(zhí)行進一步的認證流程;否則,拋出自定義異常終止認證。 

2. 編寫userService.checkLogin方法 

    public boolean checkLogin(String username, String rawPassword) throws Exception {
        SysUser userEntity = this.getUserByUserName(username);
        System.out.println("userEntity = " + userEntity);
        if (userEntity == null) {
            //System.out.println("checkLogin--------->賬號不存在,請重新嘗試!");
            //設(shè)置友好提示
            throw new Exception("賬號不存在,請重新嘗試!");
        } else {
            // 檢查賬號鎖定狀態(tài)
            handleAccountLock(userEntity);
            //加密的密碼
            String encodedPassword = userEntity.getPassword();
            //和加密后的密碼進行比配
            if (!passwordEncoder.matches(rawPassword, encodedPassword)) {
                //System.out.println("checkLogin--------->密碼不正確!");
                //設(shè)置友好提示
                throw new Exception("密碼不正確!");
            } else {
                return true;
            }
        }
    }

這段代碼實現(xiàn)了用戶登錄驗證邏輯,首先通過用戶名獲取用戶信息,如果用戶不存在則拋出異常提示賬號不存在。接著檢查用戶賬號的鎖定狀態(tài)(調(diào)用 handleAccountLock 方法),如果賬號未鎖定,則驗證用戶輸入的原始密碼是否與加密存儲的密碼匹配。密碼匹配成功則返回 true,否則拋出異常提示密碼不正確。

3.  編寫 handleAccountLock方法

    /**
     * 檢查并處理賬號鎖定邏輯
     */
    private void handleAccountLock(SysUser user) {
        if (!user.getAccountNonLocked() && user.getLockTime() != null) {
            // 當前時間
            Date now = new Date();
 
            // 解鎖時間
            Date unlockTime = new Date(user.getLockTime().getTime() + LOCK_DURATION.toMillis());
 
            if (now.before(unlockTime)) {
                throw new LockedException("賬號已鎖定,請3分鐘后再試");
            }
 
            // 解鎖賬號并重置狀態(tài)
            user.setAccountNonLocked(true);
            user.setLoginAttempts(0);
            user.setLockTime(null);
            this.updateById(user);
        }
    }

這段代碼實現(xiàn)了賬號鎖定狀態(tài)的檢查與處理邏輯。如果用戶賬號已鎖定且存在鎖定時間,系統(tǒng)會計算解鎖時間。如果當前時間在解鎖時間之前,則拋出異常提示賬號被鎖定;如果超過了解鎖時間,則解鎖賬號,同時重置失敗次數(shù)和鎖定時間,并更新用戶信息到數(shù)據(jù)庫。 

 4. 編寫increaseFailedAttempts,用于用戶登錄失敗時調(diào)用

    public void increaseFailedAttempts(SysUser user) {
        int attempts = user.getLoginAttempts() + 1;
        if (attempts >= MAX_LOGIN_ATTEMPTS) {
            user.setAccountNonLocked(false);
            user.setLockTime(new Date());
        }
        user.setLoginAttempts(attempts);
        this.updateById(user);
    }

這段代碼實現(xiàn)了增加用戶登錄失敗次數(shù)的邏輯。當用戶登錄失敗時,登錄失敗次數(shù) (loginAttempts) 增加 1;如果失敗次數(shù)達到或超過最大允許次數(shù) (MAX_LOGIN_ATTEMPTS),系統(tǒng)會將用戶賬號設(shè)置為鎖定狀態(tài) (accountNonLocked=false) 并記錄鎖定時間 (lockTime)。最后,將更新后的用戶狀態(tài)保存到數(shù)據(jù)庫。 

5. 編寫resetLoginAttempts,用于用戶登錄成功時調(diào)用

    public void resetLoginAttempts(String username) {
        SysUser user = this.getUserByUserName(username);
        if(user==null){
            throw new UsernameNotFoundException(String.format("%s.這個用戶不存在或已被禁用", username));
        }
        user.setLoginAttempts(0);
        user.setAccountNonLocked(true);
        user.setLockTime(null);
        this.updateById(user);
 
    }

這段代碼實現(xiàn)了重置用戶登錄失敗次數(shù)的邏輯。通過用戶名查詢用戶信息,如果用戶不存在則拋出異常。若用戶存在,則將其登錄失敗次數(shù) (loginAttempts) 重置為 0,解鎖賬號 (accountNonLocked=true),并清除鎖定時間 (lockTime=null)。最后,將更新后的用戶信息保存到數(shù)據(jù)庫。 

6. 編寫自定義AuthenticationSuccessHandler,在用戶登錄成功時調(diào)用resetLoginAttempts

7. 編寫自定義AuthenticationFailureHandler

@Component
public class SecurAuthenticationFailureHandler extends JSONAuthentication implements AuthenticationFailureHandler {
    @Autowired
    SysUserServiceImpl sysUserService;
 
 
    @Override
    public void onAuthenticationFailure(HttpServletRequest request,
                                        HttpServletResponse response,
                                        AuthenticationException e) throws IOException, ServletException {
 
        // 從請求體中解析 JSON,獲取 username
        String username = (String) request.getAttribute(SPRING_SECURITY_FORM_USERNAME_KEY);
        // 登錄失敗時增加失敗次數(shù)
        if (username != null) {
            SysUser user = sysUserService.getUserByUserName(username);
            if (user != null) {
                sysUserService.increaseFailedAttempts(user);
            }
        }
 
        ResponseStructure data = ResponseStructure.instance(ALL_RETURN_401.getCode(),"登錄失敗:"+e.getMessage());
        //輸出
        this.WriteJSON(request, response, data);
    }
}

這段代碼是一個自定義的登錄失敗處理器 SecurAuthenticationFailureHandler,在用戶登錄失敗時被觸發(fā)。它通過解析請求獲取登錄失敗的用戶名,并調(diào)用服務(wù)方法 increaseFailedAttempts 增加用戶的登錄失敗次數(shù)。同時,根據(jù)異常信息生成統(tǒng)一的響應(yīng)結(jié)構(gòu),并以 JSON 格式返回錯誤信息給客戶端,提示登錄失敗的原因。 

4. 結(jié)語

本文詳細講解了如何通過 Spring Security 實現(xiàn)密碼錯誤多次后自動鎖定賬號的功能。從需求分析到技術(shù)流程,再到核心代碼實現(xiàn),我們完整梳理了賬號鎖定機制的設(shè)計與落地方法。

賬號鎖定機制是提升系統(tǒng)安全性的重要手段,能夠有效防范暴力 破解攻擊。在實際應(yīng)用中,還可以結(jié)合具體需求進行優(yōu)化,例如添加解鎖通知或動態(tài)調(diào)整鎖定策略等。

以上就是Spring Security實現(xiàn)5次密碼錯誤觸發(fā)賬號自動鎖定功能的詳細內(nèi)容,更多關(guān)于Spring Security密碼錯誤賬號鎖定的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評論