国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Spring Security中異常上拋機(jī)制及對(duì)于轉(zhuǎn)型處理的一些感悟

tracymac7 / 2844人閱讀

摘要:如子異常都可以向上轉(zhuǎn)型為統(tǒng)一的驗(yàn)證異常。在設(shè)計(jì)之初的時(shí)候,驗(yàn)證類統(tǒng)一的父級(jí)異常是。兩個(gè)場(chǎng)景下的異常類關(guān)系圖譜通過上面的圖譜我們便知道了,三個(gè)異常都可以向上轉(zhuǎn)型為。向下轉(zhuǎn)型調(diào)整后的代碼在外層根據(jù)不同異常而做不同的業(yè)務(wù)處理的代碼就可以改造為如下

引言

在使用Spring Security的過程中,我們會(huì)發(fā)現(xiàn)框架內(nèi)部按照錯(cuò)誤及問題出現(xiàn)的場(chǎng)景,劃分出了許許多多的異常,但是在業(yè)務(wù)調(diào)用時(shí)一般都會(huì)向外拋一個(gè)統(tǒng)一的異常出來,為什么要這樣做呢,以及對(duì)于拋出來的異常,我們又該如何分場(chǎng)景進(jìn)行差異化的處理呢,今天來跟我一起看看吧。

Spring Security框架下的一段登錄代碼
@PostMapping("/login")
public void login(@NotBlank String username,
                    @NotBlank String password, HttpServletRequest request) {
    try {
        request.login(username, password);
        System.out.println("login success");
    } catch (ServletException authenticationFailed) {
        System.out.println("a big exception authenticationFailed");
    }
}

代碼執(zhí)行到request.login(username,password)時(shí)會(huì)跳入到了HttpServlet3RequestFactory類中,點(diǎn)擊去發(fā)現(xiàn)login方法只是統(tǒng)一向外拋出了一個(gè)ServletException異常。

public void login(String username, String password) throws ServletException {
    if (this.isAuthenticated()) {
        throw new ServletException("Cannot perform login for "" + username + "" already authenticated as "" + this.getRemoteUser() + """);
    } else {
        AuthenticationManager authManager = HttpServlet3RequestFactory.this.authenticationManager;
        if (authManager == null) {
            HttpServlet3RequestFactory.this.logger.debug("authenticationManager is null, so allowing original HttpServletRequest to handle login");
            super.login(username, password);
        } else {
            Authentication authentication;
            try {
                authentication = authManager.authenticate(new UsernamePasswordAuthenticationToken(username, password));
            } catch (AuthenticationException var6) {
                SecurityContextHolder.clearContext();
                throw new ServletException(var6.getMessage(), var6);
            }
 
            SecurityContextHolder.getContext().setAuthentication(authentication);
        }
    }
} 

authenticate()為賬號(hào)校驗(yàn)的主方法,進(jìn)入到其中的一個(gè)實(shí)現(xiàn)類ProviderManager中,會(huì)發(fā)現(xiàn)方法實(shí)際拋出是統(tǒng)一拋出的AuthenticationException異常,方法體內(nèi)實(shí)則會(huì)出現(xiàn)很多的場(chǎng)景性的異常,如AccountStatusException、InternalAuthenticationServiceException等等。

public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        Class toTest = authentication.getClass();
        AuthenticationException lastException = null;
        Authentication result = null;
        boolean debug = logger.isDebugEnabled();
        Iterator var6 = this.getProviders().iterator();
 
        while(var6.hasNext()) {
            AuthenticationProvider provider = (AuthenticationProvider)var6.next();
            if (provider.supports(toTest)) {
                if (debug) {
                    logger.debug("Authentication attempt using " + provider.getClass().getName());
                }
 
                try {
                    result = provider.authenticate(authentication);
                    if (result != null) {
                        this.copyDetails(authentication, result);
                        break;
                    }
                } catch (AccountStatusException var11) {
                    this.prepareException(var11, authentication);
                    throw var11;
                } catch (InternalAuthenticationServiceException var12) {
                    this.prepareException(var12, authentication);
                    throw var12;
                } catch (AuthenticationException var13) {
                    lastException = var13;
                }
            }
        }
 
        if (result == null && this.parent != null) {
            try {
                result = this.parent.authenticate(authentication);
            } catch (ProviderNotFoundException var9) {
                ;
            } catch (AuthenticationException var10) {
                lastException = var10;
            }
        }
 
        if (result != null) {
            if (this.eraseCredentialsAfterAuthentication && result instanceof CredentialsContainer) {
                ((CredentialsContainer)result).eraseCredentials();
            }
 
            this.eventPublisher.publishAuthenticationSuccess(result);
            return result;
        } else {
            if (lastException == null) {
                lastException = new ProviderNotFoundException(this.messages.getMessage("ProviderManager.providerNotFound", new Object[]{toTest.getName()}, "No AuthenticationProvider found for {0}"));
            }
 
            this.prepareException((AuthenticationException)lastException, authentication);
            throw lastException;
        }
    }
多態(tài)和向上轉(zhuǎn)型介紹

這里就涉及到了多態(tài)的知識(shí)點(diǎn),異常的多態(tài)。如子異常AccountStatusException都可以向上轉(zhuǎn)型為統(tǒng)一的驗(yàn)證異常AuthenticationException。

在設(shè)計(jì)之初的時(shí)候,驗(yàn)證類統(tǒng)一的父級(jí)異常是AuthenticationException。然后根據(jù)業(yè)務(wù)需求向下拓展出了很多個(gè)場(chǎng)景性質(zhì)的異常,可能有十個(gè)、一百個(gè)、一千個(gè)。

但是這些具體的場(chǎng)景異常都是從AuthenticationException延伸出來的。

在這個(gè)驗(yàn)證登陸的方法中,會(huì)驗(yàn)證各種場(chǎng)景下登陸是否合法,就有可能出現(xiàn)很多的異常場(chǎng)景,諸如:

密碼不正確 BadCredentialsException

賬號(hào)是否被鎖定 LockedException

賬號(hào)是否被禁用 DisabledException

賬號(hào)是否在有效期內(nèi) AccountExpiredException

密碼失效 CredentialsExpiredException

...幾十個(gè)幾百個(gè)異常,如果每個(gè)都需要事無巨細(xì)的拋出,那你需要在方法后面寫幾百個(gè)異常。

但是你會(huì)發(fā)現(xiàn)在驗(yàn)證方法那里統(tǒng)一拋出的是他們的統(tǒng)一父類AuthenticationException,這里用到的就是自動(dòng)的向上轉(zhuǎn)型。
到業(yè)務(wù)層我們拿到AuthenticationException后,需要進(jìn)行對(duì)特定場(chǎng)景下的業(yè)務(wù)處理,如不同的異常錯(cuò)誤返回提示不一樣,這個(gè)時(shí)候就需要用到向下轉(zhuǎn)型。

Throwable throwable = authenticationFailed.getRootCause();
if (throwable instanceof BadCredentialsException) {
    do something...
}

如果父類引用實(shí)際指的是憑證錯(cuò)誤,則進(jìn)行密碼錯(cuò)誤提示。
ServletException和AuthenticationException是兩個(gè)框架下的特定場(chǎng)景下的頂級(jí)異常,兩個(gè)怎么建立聯(lián)系呢?
答曰:直接將兩個(gè)都統(tǒng)一轉(zhuǎn)為Throwable可拋出的祖先異常,這樣向下都可以轉(zhuǎn)成他們自己了,以及各自場(chǎng)景下的所有異常了。

兩個(gè)場(chǎng)景下的異常類關(guān)系圖譜

通過上面的圖譜我們便知道了,ServletException、BadCredentialsException、DisabledException三個(gè)異常都可以向上轉(zhuǎn)型為Throwable。
那是在哪里進(jìn)行的向上類型轉(zhuǎn)換的呢?
答曰:

public void login(String username, String password) throws ServletException{
    something code ...
catch (AuthenticationException loginFailed) {
SecurityContextHolder.clearContext();
throw new ServletException(loginFailed.getMessage(), loginFailed);
}
}
 
// 在捕獲到異常之后會(huì)構(gòu)建一個(gè)ServletException并將AuthenticationException統(tǒng)一的包裝進(jìn)去,比如說內(nèi)部報(bào)了BadCredentialsException,那么在這里就會(huì)向上轉(zhuǎn)型為Throwable
public ServletException(String message, Throwable rootCause) {
    super(message, rootCause);
}
// 在Throwable類中會(huì)將最下面冒出來的異常傳給cause,getRootCause就能獲得異常的具體原因
public Throwable(String message, Throwable cause) {
    fillInStackTrace();
    detailMessage = message;
    this.cause = cause;
}

在外層邏輯處理時(shí),針對(duì)不同的業(yè)務(wù)場(chǎng)景我們便可以通過向下類型轉(zhuǎn)化來完成,如使用instanceof來驗(yàn)證對(duì)象是否是子類的實(shí)例。

// Throwable向下轉(zhuǎn)型BadCredentialsException
if (throwable instanceof BadCredentialsException)
調(diào)整后的代碼

在外層根據(jù)不同異常而做不同的業(yè)務(wù)處理的代碼就可以改造為如下

@PostMapping("/login")
public void login(@NotBlank String username,
                    @NotBlank String password, HttpServletRequest request) {
    try {
        request.login(username, password);
        System.out.println("login success");
    } catch (ServletException authenticationFailed) {
        Throwable throwable = authenticationFailed.getRootCause();
        if (throwable instanceof BadCredentialsException) {
            System.out.println("user password is wrong");
        }else if (throwable instanceof DisabledException){
            System.out.println("user is disabled");
        }else {
            System.out.println("please contact the staff");
        }
    }
}

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/72381.html

相關(guān)文章

  • Java經(jīng)典

    摘要:請(qǐng)注意,我們?cè)诹牧膯卧獪y(cè)試遇到問題多思考多查閱多驗(yàn)證,方能有所得,再勤快點(diǎn)樂于分享,才能寫出好文章。單元測(cè)試是指對(duì)軟件中的最小可測(cè)試單元進(jìn)行檢查和驗(yàn)證。 JAVA容器-自問自答學(xué)HashMap 這次我和大家一起學(xué)習(xí)HashMap,HashMap我們?cè)诠ぷ髦薪?jīng)常會(huì)使用,而且面試中也很頻繁會(huì)問到,因?yàn)樗锩嫣N(yùn)含著很多知識(shí)點(diǎn),可以很好的考察個(gè)人基礎(chǔ)。但一個(gè)這么重要的東西,我為什么沒有在一開始...

    xcold 評(píng)論0 收藏0
  • 使用Java Exception機(jī)制正確姿勢(shì)

    摘要:如何良好的在代碼中設(shè)計(jì)異常機(jī)制本身設(shè)計(jì)的出發(fā)點(diǎn)是極好的,通過編譯器的強(qiáng)制捕獲,可以明確提醒調(diào)用者處理異常情況。但使用此種異常后,該會(huì)像病毒一樣,得不到處理后會(huì)污染大量代碼,同時(shí)也可能因?yàn)檎{(diào)用者的不當(dāng)處理,會(huì)失去異常信息。 1、異常是什么? 父類為Throwable,有Error和Exception兩個(gè)子類 Error為系統(tǒng)級(jí)別的異常(錯(cuò)誤) Exception下有眾多子類,常見的有Ru...

    Astrian 評(píng)論0 收藏0
  • Java面試 32個(gè)核心必考點(diǎn)完全解析

    摘要:如問到是否使用某框架,實(shí)際是是問該框架的使用場(chǎng)景,有什么特點(diǎn),和同類可框架對(duì)比一系列的問題。這兩個(gè)方向的區(qū)分點(diǎn)在于工作方向的側(cè)重點(diǎn)不同。 [TOC] 這是一份來自嗶哩嗶哩的Java面試Java面試 32個(gè)核心必考點(diǎn)完全解析(完) 課程預(yù)習(xí) 1.1 課程內(nèi)容分為三個(gè)模塊 基礎(chǔ)模塊: 技術(shù)崗位與面試 計(jì)算機(jī)基礎(chǔ) JVM原理 多線程 設(shè)計(jì)模式 數(shù)據(jù)結(jié)構(gòu)與算法 應(yīng)用模塊: 常用工具集 ...

    JiaXinYi 評(píng)論0 收藏0
  • 關(guān)于web.xml配置那些事兒

    摘要:的版本增加了對(duì)事件監(jiān)聽程序的支持,事件監(jiān)聽程序在建立修改和刪除會(huì)話或環(huán)境時(shí)得到通知。元素指出事件監(jiān)聽程序類。過濾器配置將一個(gè)名字與一個(gè)實(shí)現(xiàn)接口的類相關(guān)聯(lián)。 1.簡(jiǎn)介 web.xml文件是Java web項(xiàng)目中的一個(gè)配置文件,主要用于配置歡迎頁(yè)、Filter、Listener、Servlet等,但并不是必須的,一個(gè)java web項(xiàng)目沒有web.xml文件照樣能跑起來。Tomcat容器/...

    zhichangterry 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<