
https://unsplash.com/photos/LmyPLbbUWhA
在開發商業邏輯時,我們經常需要知道 API 存取方的身份。舉例來說,在網路發表文章、按讚和留言,理論上都要在資料庫中紀錄「誰發的文」、「誰按的讚」和「誰留的言」,亦即資料的建立者。
本文將以 HTTP Basic 認證方式為例,示範如何從「Security Context」取得 API 存取方的使用者資料。接著準備自定義的使用者類別,以便在程式邏輯中能有更多的資料可運用。
最後透過觀察原始碼,認識 Spring Security 進行 HTTP Basic 認證的原理,讓讀者知道該認證資訊從何而來。
本文已經搬家,歡迎到「【Spring Boot】第12.4課-從 Security Context 取得 API 存取方的認證資訊」繼續閱讀。
您好,想請問一般情況下,專案針對SpringSecurity+Jwt的部分也都是會進行單元測試嗎?
回覆刪除因為要用mockMvc驗證API權限的情況下,感覺也比較偏向整合測試,
再來這邊還有一點疑問就是,
針對權限設置
http.authorizeHttpRequests(registry ->
registry.requestMatchers(HttpMethod.POST, "/users").permitAll()
這邊使用的方式是讀取資料庫權限表做動態加載,
如果要做測試勢必是不會進資料庫,那有沒有什麼方式做手動的權限配置呢?
因為預設是用.anyRequest().authenticated(),
requestMatchers沒有設置路徑會變成所有API都會被擋下
嗨嗨,如果只是想測產生或驗證 JWT 的邏輯,單元測試要寫也是可以寫
刪除但若想測試發送 request 時,是否會被 Spring Security 阻擋,那就是整合測試的範疇了,直接用 MockMvc 即可!
你會需要建立 HttpHeaders 物件,放置 access token,並將 HttpHeaders 傳入 MockMvc,詳細的用法再稍微查一下
至於後面「要做測試勢必是不會進資料庫」的問題,我沒有看懂,可以再說明一下 :)
您好,JWT測試的部分,secretKey如果不是固定字串也沒辦法驗證吧?
刪除secretKey = Keys.secretKeyFor(SignatureAlgorithm.HS256);
jwtParser = Jwts.parserBuilder().setSigningKey(secretKey).build();
因為我是用這種方式建,變成每次重啟都會變動,
沒實戰過JWT,練習單純是不想用固定字段,也不確定一般的做法是怎麼樣或有什麼規範
至於進資料庫的問題,我是想說一般做單元測試都是塞假資料或是mock,不會連資料庫,那要讀取資料庫做動態加載的部分要怎麼處理,但如果是整合測試這邊想法是直接用H2應該就可行了吧,也不會影響到測試環境的資料,就單純拿來運行測試
我覺得還是用固定字串(Keys.hmacShaKeyFor 方法)來當作 Key 好了,不然單元測試似乎不好寫。感覺要去 mock「secretKey 」的方法,但又不知該如何 mock 才好。
刪除而後面的問題,意思是你想要寫整合測試,且希望 UserDetailsServiceImpl 能連真實的 DB。但範例程式中的資料卻是 hard code 的,不知道怎麼用自己的測試資料來寫嗎?(你也可以舉例測試情境)
沒事,大致上沒問題了哈哈
刪除決定先寫controller以外的unitTest
最後再用整合測試直接測API
感謝你
作者已經移除這則留言。
回覆刪除您好!感謝您的分享,我從中收穫很多
回覆刪除這邊想要詢問比較進階的情況,就是使用H2 Databsaes跟Spring Security的時候,雖然可以Permit H2的網址,可以進入H2的登入畫面,但輸入帳密之後會無法進入控制台,都顯示Forbidden的情況,看網路上是說因為iframe被Security靜止的關係,但網路上並沒有人針對新版本的Security教如何開啟iframe,請問您可以開一個教學或者提供建議嗎~?
嗨,我沒有用過 H2 這款資料庫,可能沒辦法很好的回答。
刪除你在 Security 設定 permit H2 的網址時,API 路徑格式是如何寫的呢?記得要用「**」才能套用到底下所有路徑,比方說「/h2-console/**」。
謝謝您的分享,我已經用**套用到所有的路徑,有趣的是H2有一個登入介面,要在登入後才能操作整個資料庫,而在沒有套用/h2-console/**連登入介面都是forbidden,套用後可以進入登入介面,但登入資料庫後卻被forbidden,如果您有興趣可以嘗試引入H2的依賴玩玩看
刪除請問使用 jwt 的方式要如何在使用remember me?
刪除請問使用 jwt 的方式要如何在使用remember me?
回覆刪除嗨,你說的「remember me」是指使用者下次回到網站,不必重新登入嗎?我覺得這個需要前端來配合。
刪除前端透過登入的 API 取得 JWT 後,請瀏覽器存在 Local Storage 之類的地方。當使用者下次回來網站,就取出該 JWT,放在 request header 中即可。
由於前端不是我的專業,可能沒辦法給太多想法 :(
過半年再回來看,還是覺得springSecurity真是深不見底
回覆刪除到現在還是感謝看到這些文才能進入學習,雖然後來才發現自己基本是倒著學,一開始就配合JWT用,全部都自己手動操作,也沒真的理解無狀態,後面越看越深發現其實什麼登入驗證、session持久化,springSecurity都自動幫你做完了,一開始根本看不懂哈哈
相信再過半年回來體悟應該又會不同XD
我也是學了幾次,感覺都在一直記 Spring Security 各種物件的名詞
刪除去年參加 iThome 鐵人賽時有重寫文章,但感覺好混亂
今年學習時,又有了新認識,於是再更新文章,果然還是要循序漸進,才能學得清楚