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

SpringSecurity根據(jù)自定義異常返回登錄錯誤提示信息(賬戶鎖定)

 更新時(shí)間:2025年01月20日 09:48:23   作者:夢里花落知多少  
本文介紹了在SpringSecurity中根據(jù)自定義異常返回登錄錯誤提示信息的方法,特別是在賬戶鎖定時(shí),通過記錄輸錯次數(shù)、重寫校驗(yàn)方法并拋出自定義異常,感興趣的可以了解一下

一、背景

當(dāng)前場景:用戶在登錄失敗需要根據(jù)不同的場景返回不同的提示信息,例如賬號不存在或密碼輸錯提示 “用戶名或密碼錯誤”,賬號禁用是提示 "賬戶被鎖定"等,默認(rèn)輸錯5次密碼后賬戶會被鎖定。

需求:當(dāng)最后一次輸錯密碼時(shí)需要給用戶提示出 “xxx賬戶將被鎖定” 的提示,而不是提示 “用戶名或密碼錯誤”

分析:前四次輸錯提示 “用戶名或密碼錯誤”,第5次輸錯提示 “xxx賬戶將被鎖定”,那么需要在密碼校驗(yàn)失敗時(shí),獲取到這是第幾次輸錯

二、實(shí)現(xiàn)方案

2.1 登錄失敗記錄輸錯次數(shù)

@Component
public class LoginFailedListener implements ApplicationListener<AbstractAuthenticationFailureEvent> {

    @Autowired
    private CustomProperties customProperties ;

    @Autowired
    private UserDao userDao;

    @Override
    public void onApplicationEvent(AbstractAuthenticationFailureEvent abstractAuthenticationFailureEvent) {
        String loginName = abstractAuthenticationFailureEvent.getAuthentication()
            .getName();
        if (log.isInfoEnabled()) {
            log.info("登錄失敗 loginName=[{}]", loginName);
        }
        if (StringUtils.isBlank(loginName)) {
            return;
        }
        //查詢登錄賬號是否存在
        UserDo condition = new UserDo();
        condition.setLoginName(loginName);
        List<UserDo> userDos = userDao.selectByRecord(condition);
        if (CollectionUtils.isEmpty(userDos)) {
            return;
        }
        UserDo userDo = userDos.get(0);
        UserDo updateDo = new UserDo();
        updateDo.setUserId(userDo.getUserId());
        Integer loginFailMaxCount = customroperties.getLoginFailMaxCount();
        if (loginFailMaxCount <= userDo.getTryTime() + 1) {
            //更新用戶狀態(tài)為凍結(jié)
            updateDo.setStatus(EnumUserStatus.FORBIDDEN.getCode());
            updateDo.setTryTime(loginFailMaxCount);
            if (log.isInfoEnabled()) {
                log.info("登錄次數(shù)已達(dá)最大次數(shù):{} 凍結(jié)賬戶 loginName=[{}]", loginFailMaxCount, loginName);
            }
        } else {
            //更新嘗試次數(shù)
            updateDo.setTryTime(userDo.getTryTime() + 1);
            if (log.isInfoEnabled()) {
                log.info("嘗試次數(shù)+1 loginName=[{}], tryTime=[{}]", loginName, updateDo.getTryTime());
            }
        }
        updateDo.setUpdateTime(new Date());
        userDao.updateBySelective(updateDo);
    }
}

2.2 重寫校驗(yàn)方法,滿足條件時(shí)拋出自定義異常

  • 校驗(yàn)拋出的異常一定要是AuthenticationException及其子類
  • 因?yàn)閯?chuàng)建了監(jiān)聽器ApplicationListener的實(shí)現(xiàn),源碼中回調(diào)是有條件的,所以最后最好是原樣拋出 BadCredentialsException ,否則ApplicationListener將不會被觸發(fā)
@Slf4j
public class CustomDaoAuthenticationProvider extends DaoAuthenticationProvider {

    @Autowired
    private CustomProperties customProperties ;

    @Override
    protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
        try {
            super.additionalAuthenticationChecks(userDetails, authentication);
        } catch (AuthenticationException e) {
            if(e instanceof BadCredentialsException && userDetails instanceof UserDto){
                UserDto userDto = (UserDto) userDetails;
                //先到這里,然后去觸發(fā)LoginFailedListener,達(dá)到賬戶被鎖定這里需要+1
                //已經(jīng)被凍結(jié)的不處理,只處理正常用戶,并且是達(dá)到最大失敗次數(shù)的那一次
                if(EnumUserStatus.NORMAL.getCode().equals(userDto.getStatus()) && Objects.equals(userDto.getTryTime() + 1, customProperties .getLoginFailMaxCount())){
                    if(log.isErrorEnabled()){
                        log.error("用戶:{} 登錄失敗次數(shù)已達(dá)最大,賬戶將被鎖定", userDto.getLoginName());
                    }
                    throw new BadCredentialsException(e.getMessage(), new LoginFailCountOutException("登錄失敗次數(shù)已達(dá)最大"));
                }else {
                    throw e;
                }

            }else {
                throw e;
            }

        }
    }


}

public class LoginFailCountOutException extends AuthenticationException {
    private static final long serialVersionUID = -8546980609242201580L;

    /**
     * Constructs an {@code AuthenticationException} with the specified message and no
     * root cause.
     *
     * @param msg the detail message
     */
    public LoginFailCountOutException(String msg) {
        super(msg);
    }

    public LoginFailCountOutException(String msg, Throwable ex) {
        super(msg, ex);
    }
}

2.3 裝配自定義的AuthenticationProvider

@Bean
    public AuthenticationProvider authenticationProvider(UserDetailsService userDetailsService, PasswordEncoder passwordEncoder, UserAuthoritiesMapper userAuthoritiesMapper) {
        DaoAuthenticationProvider authenticationProvider = new CustomDaoAuthenticationProvider();
        // 對默認(rèn)的UserDetailsService進(jìn)行覆蓋
        authenticationProvider.setUserDetailsService(userDetailsService);
        authenticationProvider.setPasswordEncoder(passwordEncoder);
        authenticationProvider.setAuthoritiesMapper(userAuthoritiesMapper);
        return authenticationProvider;
    }

WebSecurityConfigurerAdapter 的配置類中注入

@Autowired
    private AuthenticationProvider authenticationProvider;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(authenticationProvider);
    }

2.4 AuthenticationFailureHandler 根據(jù)異常返回提示

failureHandler((request, response, ex) -> {
                response.setContentType("application/json;charset=utf-8");
                PrintWriter out = response.getWriter();
                String errorMessage = this.loginFailureErrorMessage(ex);
                out.write(JSON.toJSONString(Response.<Void>builder().isSuccess(false)
                    .errorMessage(errorMessage)
                    .build()));
                out.flush();
                out.close();
            })

private String loginFailureErrorMessage(AuthenticationException ex) {
        if (ex instanceof UsernameNotFoundException || ex instanceof BadCredentialsException) {
            if(ex.getCause() != null && ex.getCause() instanceof LoginFailCountOutException){
                return "登錄失敗次數(shù)已達(dá)最大限制, 賬戶凍結(jié)";
            }
            return "用戶名或密碼錯誤";
        }
        if (ex instanceof DisabledException) {
            return "賬戶被禁用";
        }
        if (ex instanceof LockedException) {
            return "賬戶被鎖定";
        }
        if (ex instanceof AccountExpiredException) {
            return "賬戶已過期";
        }
        if (ex instanceof CredentialsExpiredException) {
            return "密碼已過期";
        }
        log.warn("不明原因登錄失敗", ex);
        return "登錄失敗";
    }

到此這篇關(guān)于SpringSecurity根據(jù)自定義異常返回登錄錯誤提示信息(賬戶鎖定)的文章就介紹到這了,更多相關(guān)SpringSecurity自定義異常返回登錄錯誤提示內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 關(guān)于在使用Lombok時(shí)maven?install找不到符號問題的解決辦法

    關(guān)于在使用Lombok時(shí)maven?install找不到符號問題的解決辦法

    Maven環(huán)境下開發(fā)項(xiàng)目時(shí),尤其是涉及Lombok或其他依賴時(shí),IDE會在構(gòu)建和編譯過程中進(jìn)行注解處理,這篇文章主要介紹了關(guān)于在使用Lombok時(shí)maven?install找不到符號問題的解決辦法,需要的朋友可以參考下
    2025-10-10
  • java顯示當(dāng)前美國洛杉磯時(shí)間

    java顯示當(dāng)前美國洛杉磯時(shí)間

    這篇文章主要介紹了java顯示當(dāng)前美國洛杉磯時(shí)間的方法,也就是當(dāng)前時(shí)間的切換,需要的朋友可以參考下
    2014-02-02
  • 200行Java代碼如何實(shí)現(xiàn)依賴注入框架詳解

    200行Java代碼如何實(shí)現(xiàn)依賴注入框架詳解

    依賴注入對大家來說應(yīng)該都不陌生,下面這篇文章主要給大家介紹了關(guān)于利用200行Java代碼如何實(shí)現(xiàn)依賴注入框架的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-05-05
  • 關(guān)于SpringBoot中的XA事務(wù)詳解

    關(guān)于SpringBoot中的XA事務(wù)詳解

    這篇文章主要介紹了關(guān)于SpringBoot中的XA事務(wù)詳解,事務(wù)管理可以確保數(shù)據(jù)的一致性和完整性,同時(shí)也可以避免數(shù)據(jù)丟失和沖突等問題。在分布式環(huán)境中,XA?事務(wù)是一種常用的事務(wù)管理方式,需要的朋友可以參考下
    2023-07-07
  • IDEA類和方法注釋模板設(shè)置(非常詳細(xì))

    IDEA類和方法注釋模板設(shè)置(非常詳細(xì))

    這篇文章主要介紹了IDEA類和方法注釋模板設(shè)置(非常詳細(xì)),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-08-08
  • mybatis-plus數(shù)據(jù)權(quán)限實(shí)現(xiàn)代碼

    mybatis-plus數(shù)據(jù)權(quán)限實(shí)現(xiàn)代碼

    這篇文章主要介紹了mybatis-plus數(shù)據(jù)權(quán)限實(shí)現(xiàn),結(jié)合了mybatis-plus的插件方式,做出了自己的注解方式的數(shù)據(jù)權(quán)限,雖然可能存在一部分的局限性,但很好的解決了我們自己去解析SQL的功能,需要的朋友可以參考下
    2023-06-06
  • javaweb 項(xiàng)目初始配置的方法步驟

    javaweb 項(xiàng)目初始配置的方法步驟

    本文主要介紹了javaweb 項(xiàng)目初始配置的方法步驟,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-11-11
  • Java實(shí)現(xiàn)檢查多個時(shí)間段是否有重合

    Java實(shí)現(xiàn)檢查多個時(shí)間段是否有重合

    這篇文章主要為大家詳細(xì)介紹了如何使用Java實(shí)現(xiàn)檢查多個時(shí)間段是否有重合,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2025-02-02
  • 詳解Java的構(gòu)造方法及類的初始化

    詳解Java的構(gòu)造方法及類的初始化

    這篇文章主要為大家詳細(xì)介紹了Java的構(gòu)造方法及類的初始化,文中的示例代碼講解詳細(xì),對我們學(xué)習(xí)Java有一定的幫助,感興趣的小伙伴可以了解一下
    2022-08-08
  • Java反射機(jī)制核心類Class、Constructor、Method、Field詳解

    Java反射機(jī)制核心類Class、Constructor、Method、Field詳解

    反射機(jī)制是Java語言的一項(xiàng)強(qiáng)大特性,允許程序在運(yùn)行時(shí)動態(tài)地加載、探知和使用類或者對象的信息,這篇文章主要介紹了Java反射機(jī)制核心類Class、Constructor、Method、Field的相關(guān)資料,需要的朋友可以參考下
    2025-12-12

最新評論

克山县| 凌海市| 江口县| 射洪县| 额尔古纳市| 阿拉善右旗| 涿州市| 临潭县| 萍乡市| 崇阳县| 长治市| 荥阳市| 屯门区| 嘉兴市| 渭南市| 都江堰市| 达孜县| 和龙市| 恩施市| 英山县| 子长县| 安化县| 崇义县| 长治市| 任丘市| 柳州市| 保定市| 星座| 东宁县| 阜康市| 翁源县| 正安县| 象山县| 临洮县| 襄城县| 海兴县| 长顺县| 抚顺市| 潼南县| 日土县| 徐汇区|