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

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

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

一、背景

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

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

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

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

2.1 登錄失敗記錄輸錯(cuò)次數(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;
        }
        //查詢登錄賬號(hào)是否存在
        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 重寫(xiě)校驗(yàn)方法,滿足條件時(shí)拋出自定義異常

  • 校驗(yàn)拋出的異常一定要是AuthenticationException及其子類
  • 因?yàn)閯?chuàng)建了監(jiān)聽(tīng)器ApplicationListener的實(shí)現(xiàn),源碼中回調(diào)是有條件的,所以最后最好是原樣拋出 BadCredentialsException ,否則ApplicationListener將不會(huì)被觸發(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();
        // 對(duì)默認(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 "用戶名或密碼錯(cuò)誤";
        }
        if (ex instanceof DisabledException) {
            return "賬戶被禁用";
        }
        if (ex instanceof LockedException) {
            return "賬戶被鎖定";
        }
        if (ex instanceof AccountExpiredException) {
            return "賬戶已過(guò)期";
        }
        if (ex instanceof CredentialsExpiredException) {
            return "密碼已過(guò)期";
        }
        log.warn("不明原因登錄失敗", ex);
        return "登錄失敗";
    }

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

相關(guān)文章

  • java?byte數(shù)組轉(zhuǎn)String的幾種常用方法

    java?byte數(shù)組轉(zhuǎn)String的幾種常用方法

    在Java中數(shù)組是一種非常常見(jiàn)的數(shù)據(jù)結(jié)構(gòu),它可以用來(lái)存儲(chǔ)多個(gè)相同類型的數(shù)據(jù),有時(shí)候,我們需要將數(shù)組轉(zhuǎn)換為字符串,以便于輸出或者傳遞給其他方法,這篇文章主要給大家介紹了關(guān)于java?byte數(shù)組轉(zhuǎn)String的幾種常用方法,需要的朋友可以參考下
    2024-09-09
  • java訪問(wèn)者模式的靜態(tài)動(dòng)態(tài)及偽動(dòng)態(tài)分派徹底理解

    java訪問(wèn)者模式的靜態(tài)動(dòng)態(tài)及偽動(dòng)態(tài)分派徹底理解

    這篇文章主要為大家介紹了java訪問(wèn)者模式的靜態(tài)動(dòng)態(tài)及偽動(dòng)態(tài)分派徹底理解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-06-06
  • gateway與spring-boot-starter-web沖突問(wèn)題的解決

    gateway與spring-boot-starter-web沖突問(wèn)題的解決

    這篇文章主要介紹了gateway與spring-boot-starter-web沖突問(wèn)題的解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • SpringMVC的ModelAndView傳值方法

    SpringMVC的ModelAndView傳值方法

    今天小編就為大家分享一篇SpringMVC的ModelAndView傳值方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-08-08
  • Java利用DelayQueue實(shí)現(xiàn)延遲任務(wù)代碼實(shí)例

    Java利用DelayQueue實(shí)現(xiàn)延遲任務(wù)代碼實(shí)例

    這篇文章主要介紹了Java利用DelayQueue實(shí)現(xiàn)延遲任務(wù)代碼實(shí)例,DelayQueue?是一個(gè)支持延時(shí)獲取元素的阻塞隊(duì)列,?內(nèi)部采用優(yōu)先隊(duì)列?PriorityQueue?存儲(chǔ)元素,同時(shí)元素必須實(shí)現(xiàn)?Delayed?接口,需要的朋友可以參考下
    2023-12-12
  • 應(yīng)用Java泛型和反射導(dǎo)出CSV文件的方法

    應(yīng)用Java泛型和反射導(dǎo)出CSV文件的方法

    這篇文章主要介紹了應(yīng)用Java泛型和反射導(dǎo)出CSV文件的方法,通過(guò)一個(gè)自定義函數(shù)結(jié)合泛型與反射的應(yīng)用實(shí)現(xiàn)導(dǎo)出CSV文件的功能,具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2014-12-12
  • Spring發(fā)送郵件如何內(nèi)嵌圖片增加附件

    Spring發(fā)送郵件如何內(nèi)嵌圖片增加附件

    這篇文章主要介紹了Spring發(fā)送郵件如何內(nèi)嵌圖片增加附件,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-10-10
  • SpringCloud讀取Nacos配置中心報(bào)錯(cuò)及遇到的坑:Could?not?resolve?placeholder?‘xxx’?in?value?‘${xxx}

    SpringCloud讀取Nacos配置中心報(bào)錯(cuò)及遇到的坑:Could?not?resolve?placehold

    這篇文章主要介紹了SpringCloud讀取Nacos配置中心報(bào)錯(cuò):Could?not?resolve?placeholder?‘xxx’?in?value?‘${xxx},本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-03-03
  • SpringBoot全局異常處理機(jī)制和配置攔截器方式

    SpringBoot全局異常處理機(jī)制和配置攔截器方式

    這篇文章主要介紹了SpringBoot全局異常處理機(jī)制和配置攔截器方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-12-12
  • 詳解Java ArrayList類

    詳解Java ArrayList類

    這篇文章主要介紹了Java ArrayList類的相關(guān)資料,文中示例代碼非常詳細(xì),幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下
    2020-07-07

最新評(píng)論