SpringBoot集成Spring Security(3)——異常處理


源碼地址:https://github.com/jitwxs/blog_sample

文章目錄

一、常見異常
二、源碼分析
三、處理異常
不知道你有沒有注意到,當我們登陸失敗時候,Spring security 幫我們跳轉到了 /login?error Url,奇怪的是不管是控制台還是網頁上都沒有打印錯誤信息。

錯誤頁面

這是因為首先 /login?error 是 Spring security 默認的失敗 Url,其次如果你不手動處理這個異常,這個異常是不會被處理的。

一、常見異常

我們先來列舉下一些 Spring Security 中常見的異常:

  • UsernameNotFoundException(用戶不存在)
  • DisabledException(用戶已被禁用)
  • BadCredentialsException(壞的憑據)
  • LockedException(賬戶鎖定)
  • AccountExpiredException (賬戶過期)
  • CredentialsExpiredException(證書過期)


以上列出的這些異常都是 AuthenticationException 的子類,然后我們來看看 Spring security 如何處理 AuthenticationException 異常的。

 

二、源碼分析

我們知道異常處理一般在過濾器中處理,我們在 AbstractAuthenticationProcessingFilter 中找到了對 AuthenticationException 的處理:

(1)在 doFilter() 中,捕捉了 AuthenticationException 異常,並交給了 unsuccessfulAuthentication() 處理。
doFilter()

 

(2)在 unsuccessfulAuthentication() 中,轉交給了 SimpleUrlAuthenticationFailureHandler 類的 onAuthenticationFailure() 處理。

unsuccessfulAuthentication()

 

(3)在onAuthenticationFailure()中,首先判斷有沒有設置defaultFailureUrl

  • 如果沒有設置,直接返回 401 錯誤,即 HttpStatus.UNAUTHORIZED 的值。
  • 如果設置了,首先執行 saveException() 方法。然后判斷 forwardToDestination ,即是否是服務器跳轉,默認使用重定向即客戶端跳轉。

onAuthenticationFailure()

 

(4)在 saveException() 方法中,首先判斷forwardToDestination,如果使用服務器跳轉則寫入 Request,客戶端跳轉則寫入 Session。寫入名為 SPRING_SECURITY_LAST_EXCEPTION ,值為 BadCredentialsException
saveException()

 

至此 Spring security 完成了異常處理,總結一下流程:

–> AbstractAuthenticationProcessingFilter.doFilter()

–> AbstractAuthenticationProcessingFilter.unsuccessfulAuthentication()

–> SimpleUrlAuthenticationFailureHandler.onAuthenticationFailure()

–> SimpleUrlAuthenticationFailureHandler.saveException()

三、處理異常

上面源碼說了那么多,真正處理起來很簡單,我們只需要指定錯誤的url,然后再該方法中對異常進行處理即可。

(1)指定錯誤Url,WebSecurityConfig中添加.failureUrl("/login/error")

...
@Override
protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests()
            // 如果有允許匿名的url,填在下面
//                .antMatchers().permitAll()
            .anyRequest().authenticated()
            .and()
            // 設置登陸頁
            .formLogin().loginPage("/login")
            // 設置登陸成功頁
            .defaultSuccessUrl("/").permitAll()
            // 登錄失敗Url
            .failureUrl("/login/error")
            // 自定義登陸用戶名和密碼參數,默認為username和password
//                .usernameParameter("username")
//                .passwordParameter("password")
            .and()
            .logout().permitAll()
            // 自動登錄
            .and().rememberMe()
                .tokenRepository(persistentTokenRepository())
                // 有效時間:單位s
                .tokenValiditySeconds(60)
                .userDetailsService(userDetailsService);

    // 關閉CSRF跨域
    http.csrf().disable();
}
...

 

(2)在Controller中處理異常

@RequestMapping("/login/error")
public void loginError(HttpServletRequest request, HttpServletResponse response) {
    response.setContentType("text/html;charset=utf-8");
    AuthenticationException exception =
            (AuthenticationException)request.getSession().getAttribute("SPRING_SECURITY_LAST_EXCEPTION");
    try {
        response.getWriter().write(exception.toString());
    }catch (IOException e) {
        e.printStackTrace();
    }
}

 

我們首先獲取了 session 中的 SPRING_SECURITY_LAST_EXCEPTION 。為了演示,我只是簡單的將錯誤信息返回給了頁面。運行程序,當我們輸入錯誤密碼時:

錯誤信息

 

---------------------
作者:Jitwxs
來源:CSDN
原文:https://blog.csdn.net/yuanlaijike/article/details/80250389


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM