Spring Security 02 - Security Context? 從哪來?

上回我們說了SecurityContextHolder主要在做什麼,這回主要討論的是,SecurityContext到底是何方神聖,它從何而來。 SecurityContext它作為 Spring Security 核心中的一部分,它的作用可說是非常重要的。我們來看看SecurityContext的源碼。 public interface SecurityContext extends Serializable { /** * 獲取當前已驗證的身分或驗證請求令牌 * * @return the <code>Authentication</code> or <code>null</code> if no authentication * information is available */ Authentication getAuthentication(); /** * 改變目前已驗證的身分或刪除驗證資料 * * @param authentication the new <code>Authentication</code> token, or * <code>null</code> if no further authentication information should be stored */ void setAuthentication(Authentication authentication); } 可以看到SecurityContext主要是在管理Authentication的物件,那這個Authentication主要是存放當前使用者的身分(廢話)、存放是否已驗證以及取得目前使用者擁有的權限。 那 SecurityContext 從何而來呢? 同個包內的SecurityContextImpl就是它的實現,裡面都是很基本的邏輯,這次就不放了,可從官方GitHub找到相關源代碼。 那如何在不同request之間保存SecurityContext呢? 在Spring Security主要有兩個在不同request之間保存SecurityContext的策略,這邊簡單介紹一下,兩者都是ServerSecurityContextRepository的實現。 NoOpServerSecurityContextRepository: 很廢,當你叫它保存的時候它不會理你,左耳進右耳出,然後你問他那個東西在哪,它會直接說"我不知道,你有跟我講過嗎?",通常用於無狀態(Stateless)驗證,例如:httpBasic。 WebSessionServerSecurityContextRepository: 好學生,你叫它保存的時候,它會幫你做三件事,1. 取得當前Session -> 2....

October 8, 2020 · 1 min · Aitay

Spring Security 01 - 關於 ReactiveSecurityContextHolder 的一兩件事

Spring Security對於寫過Spring Boot的人應該是再熟悉不過了,這篇文主要紀錄我對於 ReactiveSecurityContextHolder的理解,原始碼版本為5.4.0-RC1。 在聊原始碼前,我想先聊一下Context到底是什麼。 Context,中文譯作「上下文」,我對於上下文的理解就是物件作用的環境。 打個比方,假設現在有一個物件叫做Weather,而假設Weather物件會有下雨、晴朗這兩種狀態,且EarthContext封裝其物件或者是強制其改變為某種狀態時,則可以說Weather的上下文是EarthContext。 對於Spring Security來說,SecurityContext就是整個Spring Security應用的上下文。 而SecurityContextHolder就是單純保存這個上下文而存在的。 在傳統Servlet應用SecurityContextHolder是存在多種保存上下文的策略,比方說GlobalSecurityContextHolderStrategy、InheritableThreadLocalSecurityContextHolderStrategy跟ThreadLocalSecurityContextHolderStrategy,但在ReactiveSecurityContextHolder中,並沒有多種策略去保存SecurityContext,唯一保存上下文的方法就是透過Reactor的上下文。 以下為個人部分翻譯的源碼: public class ReactiveSecurityContextHolder { private static final Class<?> SECURITY_CONTEXT_KEY = SecurityContext.class; /** * 從 Reactor {@link Context} 取得 {@code Mono<SecurityContext>} * @return 回傳 {@code Mono<SecurityContext>} */ public static Mono<SecurityContext> getContext() { // 從Reactor的上下文中取得SecurityContext return Mono.subscriberContext() .filter( c -> c.hasKey(SECURITY_CONTEXT_KEY)) .flatMap( c-> c.<Mono<SecurityContext>>get(SECURITY_CONTEXT_KEY)); } /** * 從 Reactor {@link Context} 清除 {@code Mono<SecurityContext>} * @return 清除Reactor上下文,並回傳一個 Mono<Void>,若清除失敗,則報錯。 */ public static Function<Context, Context> clearContext() { // 從Reactor的上下文中刪除SecurityContext return context -> context....

October 6, 2020 · 1 min · Aitay