源碼地址: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() 處理。
(2)在 unsuccessfulAuthentication()
中,轉交給了 SimpleUrlAuthenticationFailureHandler
類的 onAuthenticationFailure()
處理。
(3)在onAuthenticationFailure()中,首先判斷有沒有設置defaultFailureUrl。
- 如果沒有設置,直接返回 401 錯誤,即 HttpStatus.UNAUTHORIZED 的值。
- 如果設置了,首先執行 saveException() 方法。然后判斷 forwardToDestination ,即是否是服務器跳轉,默認使用重定向即客戶端跳轉。
(4)在 saveException() 方法中,首先判斷forwardToDestination,如果使用服務器跳轉則寫入 Request,客戶端跳轉則寫入 Session。寫入名為 SPRING_SECURITY_LAST_EXCEPTION ,值為 BadCredentialsException。
至此 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