在代碼里,我們沒有認證或者授權的filter。認證和授權的工作現在基本上完全由Spring Security的過濾器接管了。
本節就來看下 如何在Spring Security的過濾器鏈上加入我們自己的邏輯,因為現在這個過濾器鏈上只處理了認證和授權。我們還有其他的一些安全機制,比如說限流、日志。我們看下怎么把這些機制加到Spring的默認實現里面去,最后總結一下,到底都做了哪些事情,然后整個它的處理流程是什么樣子的
日志
首先來寫處理日志的過濾器。和我們之前的處理是類似的。
繼承OncePerRequestFilter
這里一定注意不要用@Component注解把這個Filter聲明成Spring 的Bean原因下面再講。
日志的這個過濾器應該是在認證的過濾器前面,在授權的過濾器前面。所以在這個過濾器里面,我應該知道當前用戶是誰了。如果你的認證成功的話。
前面認證的過濾器會把jwt的令牌轉換成一個Authentication,然后把它放到SpringSecurityContext安全的上下文里面。
通過下面的代碼就可以把它從安全上下文里面再拿出來。principal就是我們申請令牌的時候的用戶名。
調用后面的過濾器處理完之后,還要再加一句日志更新,日志的成功還是失敗,更新到數據庫里面。這里我簡單的用一個sysout來處理。把日志更新成處理成功。
過濾器加到SpringSecurity配置中
http的安全配置這里加一行。第一個addFilter一般不會去用.
addFilterAfter、addFilterAt、addFilterBefore 就是你自己寫的過濾器加到SpringSecurity的過濾器鏈上,指定一個位置。SpringSecurity過濾器鏈的順序是固定的。所以你只要把你的過濾器加到spring的某一個過濾器的前面before或 后面after,at就是直接加入到這個過濾器的位置上。替換掉原來的過濾器。
我們加的是一個日志過濾器,要加載授權的前面。用addFilterBefore
前面是自己定義的過濾器,后面那個過濾器ExceptionTranslationFilter是Spring 用來轉換異常的一個過濾器。我們最后會在授權的過濾器里面拋出異常。要不然是401需要身份認證,要不然是403需要權限。就這兩種異常。兩個異常拋出來以后,都會由這個過濾器來處理。
剛才我們說不要把自己定義的GatewayAuditLogFilter聲明稱一個spring的Bean。SprintBoot默認情況下(如果聲明成了Spring的Bean) ,會把這個過濾器直接加到web程序的過濾器鏈上。因為這個類繼承了OncePreRequestFilter
后面這里還有一個addFilter的操作。也就是說SpringBoot加了一次,自己這里寫代碼又加了一次。這個過濾器加入到過濾器的鏈上,加了兩次。所以我們這里不聲明稱Spring成的Bean。這里只用代碼加到鏈上一次。
啟動測試
首先是 認證服務器
網關
訂單。
申請令牌
復制令牌
去調用創建訂單的服務。
看一下 網關上的日志。說明進入了日志的過濾器里面。jojo是jwt內解析的用戶名, 這說明日志是在認證的過濾器后面的。所以才會解析出當前的用戶。
第二句是在驗證權限的服務,這里打印出來的。這就說明了日志過濾器在認證的過濾器之后,權限的過濾器之前生效的。
在權限的過濾器判斷完成后,最終還會回到日志的過濾器里面,把它的處理結果更新成處理成功。這個是我們想要的執行的順序。
異常處理
多發幾次創建訂單的請求,因為是50%的成功率
403訪問被拒絕。
這里並沒有體現出來,請求是被拒絕掉的、現在的處理代碼並沒有處理這種情況,仍然是回到了日志Filter里面,把我的日志更新成功了。
這個就是訪問被拒絕 ,它的處理器
默認的處理器就是返回下面這樣的json
我們可以自己定義自己的訪問拒絕的處理器。在這個處理器里面我們可以記錄日志,也可以自定義返回去的這個錯誤。這里只是針對沒有權限403這種情況的一個處理。
還有另外一種情況401,一會再說。
我們要寫的就是AccessDeniedHandler這個接口的實現。
自定義錯誤處理handler
直接繼承一個父類。
OAuth2AccessDeniedHandler是個默認的實現,如果不在網關的這里配置accessDeniedHandler這個配置的話。
默認用的就是這個 OAuth2AccessDeniedHandler。在這里處理器里面,它會把異常 轉換成一個簡單的json也就是我們看到頁面返回的403的json
聲明稱Spring的Bean。然后覆蓋handler方法。
在這里能拿到request、response、拋出的exception。
可以通過操作response,寫你想寫的錯誤信息。
這里我們就加一句輸出
注入我們自己寫的錯誤處理器
這樣在拋出403的錯誤異常的時候,我的控制台就會輸出。
重啟網關服務。測試
日志的過濾器里面又update了一次。更新為成功了。我們想要的是 如果報錯了 就不再更新日志為成功
最簡單的做法是在request里面設置一個attributes。value值隨便定義。
attribute的值為空 就走更新成功。也就是沒有拋出403的錯誤。
重啟網關服務
結束