身份驗證永續性和會話管理

一旦你有一個認證請求的應用程式,考慮如何持久化並恢復該認證以用於未來的請求是很重要的。

預設情況下,這是自動完成的,因此不需要額外的程式碼,儘管瞭解HttpSecurityrequireExplicitSave的含義很重要。

如果你願意,你可以閱讀更多關於requireExplicitSave的作用它為何重要。否則,在大多數情況下,你已經完成了本節內容。

但在離開之前,請考慮以下任何用例是否適合你的應用程式

瞭解會話管理的元件

會話管理支援由一些協同工作的元件組成,以提供功能。這些元件是SecurityContextHolderFilterSecurityContextPersistenceFilterSessionManagementFilter

在Spring Security 6中,SecurityContextPersistenceFilterSessionManagementFilter預設未設定。此外,任何應用程式都應該只設置SecurityContextHolderFilterSecurityContextPersistenceFilter,兩者不能同時設定。

SessionManagementFilter

SessionManagementFilter根據SecurityContextHolder的當前內容檢查SecurityContextRepository的內容,以確定使用者是否在當前請求期間進行了身份驗證,通常是透過非互動式身份驗證機制,例如預身份驗證或記住我[1]。如果倉庫包含安全上下文,過濾器不執行任何操作。如果它不包含,並且執行緒本地SecurityContext包含一個(非匿名)Authentication物件,過濾器假定它們已被堆疊中的前一個過濾器進行身份驗證。然後它將呼叫配置的SessionAuthenticationStrategy

如果使用者當前未進行身份驗證,過濾器將檢查是否請求了無效的會話ID(例如,由於超時),並且如果設定了InvalidSessionStrategy,則會呼叫它。最常見的行為是重定向到固定URL,這封裝在標準實現SimpleRedirectInvalidSessionStrategy中。後者也用於透過名稱空間配置無效會話URL時,如前所述

擺脫SessionManagementFilter

在Spring Security 5中,預設配置依賴於SessionManagementFilter來檢測使用者是否剛剛進行了身份驗證並呼叫SessionAuthenticationStrategy。這樣做的問題是,這意味著在典型的設定中,每個請求都必須讀取HttpSession

在Spring Security 6中,預設是身份驗證機制本身必須呼叫SessionAuthenticationStrategy。這意味著不需要檢測Authentication何時完成,因此每個請求都不需要讀取HttpSession

擺脫SessionManagementFilter時需要考慮的事項

在Spring Security 6中,預設不使用SessionManagementFilter,因此,sessionManagement DSL中的某些方法將不會產生任何效果。

方法 替代

sessionAuthenticationErrorUrl

在您的身份驗證機制中配置一個AuthenticationFailureHandler

sessionAuthenticationFailureHandler

在您的身份驗證機制中配置一個AuthenticationFailureHandler

sessionAuthenticationStrategy

上文討論,在您的身份驗證機制中配置一個SessionAuthenticationStrategy

如果您嘗試使用這些方法中的任何一個,將會丟擲異常。

自定義身份驗證儲存位置

預設情況下,Spring Security 會將安全上下文儲存在 HTTP 會話中。但是,您可能出於以下幾個原因想要自定義它

  • 您可能希望在HttpSessionSecurityContextRepository例項上呼叫單個 setter

  • 您可能希望將安全上下文儲存在快取或資料庫中,以實現水平擴充套件

首先,您需要建立SecurityContextRepository的實現或使用現有實現(如HttpSessionSecurityContextRepository),然後可以在HttpSecurity中進行設定。

自定義SecurityContextRepository
  • Java

  • Kotlin

  • XML

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) {
    SecurityContextRepository repo = new MyCustomSecurityContextRepository();
    http
        // ...
        .securityContext((context) -> context
            .securityContextRepository(repo)
        );
    return http.build();
}
@Bean
open fun filterChain(http: HttpSecurity): SecurityFilterChain {
    val repo = MyCustomSecurityContextRepository()
    http {
        // ...
        securityContext {
            securityContextRepository = repo
        }
    }
    return http.build()
}
<http security-context-repository-ref="repo">
    <!-- ... -->
</http>
<bean name="repo" class="com.example.MyCustomSecurityContextRepository" />

上述配置在SecurityContextHolderFilter和**參與的**身份驗證過濾器(例如UsernamePasswordAuthenticationFilter)上設定了SecurityContextRepository。要同時在無狀態過濾器中設定它,請參閱如何為無狀態身份驗證自定義SecurityContextRepository

如果您正在使用自定義身份驗證機制,您可能希望自己儲存Authentication

手動儲存Authentication

在某些情況下,例如,您可能正在手動驗證使用者,而不是依賴 Spring Security 過濾器。您可以使用自定義過濾器或Spring MVC 控制器端點來完成此操作。如果您想在請求之間(例如在HttpSession中)儲存身份驗證,則必須這樣做

  • Java

private SecurityContextRepository securityContextRepository =
        new HttpSessionSecurityContextRepository(); (1)

@PostMapping("/login")
public void login(@RequestBody LoginRequest loginRequest, HttpServletRequest request, HttpServletResponse response) { (2)
    UsernamePasswordAuthenticationToken token = UsernamePasswordAuthenticationToken.unauthenticated(
        loginRequest.getUsername(), loginRequest.getPassword()); (3)
    Authentication authentication = authenticationManager.authenticate(token); (4)
    SecurityContext context = securityContextHolderStrategy.createEmptyContext();
    context.setAuthentication(authentication); (5)
    securityContextHolderStrategy.setContext(context);
    securityContextRepository.saveContext(context, request, response); (6)
}

class LoginRequest {

    private String username;
    private String password;

    // getters and setters
}
1 SecurityContextRepository新增到控制器中
2 注入HttpServletRequestHttpServletResponse以便能夠儲存SecurityContext
3 使用提供的憑據建立未經身份驗證的UsernamePasswordAuthenticationToken
4 呼叫AuthenticationManager#authenticate來驗證使用者
5 建立一個SecurityContext並在其中設定Authentication
6 SecurityContext儲存到SecurityContextRepository

就是這樣。如果您不確定上述示例中的securityContextHolderStrategy是什麼,您可以在使用SecurityContextStrategy一節中閱讀更多資訊。

正確清除身份驗證

如果您正在使用Spring Security的登出支援,那麼它會為您處理很多事情,包括清除和儲存上下文。但是,假設您需要手動將使用者從應用程式中登出。在這種情況下,您需要確保正確清除和儲存上下文

配置無狀態身份驗證的永續性

有時,無需建立和維護HttpSession來跨請求持久化身份驗證。某些身份驗證機制,如HTTP Basic,是無狀態的,因此在每個請求上都會重新驗證使用者。

如果您不希望建立會話,可以使用SessionCreationPolicy.STATELESS,如下所示

  • Java

  • Kotlin

  • XML

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) {
    http
        // ...
        .sessionManagement((session) -> session
            .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
        );
    return http.build();
}
@Bean
open fun filterChain(http: HttpSecurity): SecurityFilterChain {
    http {
        // ...
        sessionManagement {
            sessionCreationPolicy = SessionCreationPolicy.STATELESS
        }
    }
    return http.build()
}
<http create-session="stateless">
    <!-- ... -->
</http>

上述配置配置了SecurityContextRepository以使用NullSecurityContextRepository,並且還阻止了請求被儲存到會話中

如果您正在使用SessionCreationPolicy.NEVER,您可能會注意到應用程式仍在建立HttpSession。在大多數情況下,這是因為請求被儲存到會話中,以便在身份驗證成功後重新請求已認證的資源。為了避免這種情況,請參閱如何阻止請求被儲存一節。

將會話中的無狀態身份驗證儲存

如果由於某種原因,您正在使用無狀態身份驗證機制,但仍然希望將會話中的身份驗證儲存起來,則可以使用HttpSessionSecurityContextRepository而不是NullSecurityContextRepository

對於HTTP Basic,您可以新增一個ObjectPostProcessor來更改BasicAuthenticationFilter使用的SecurityContextRepository

將 HTTP Basic 身份驗證儲存在 HttpSession
  • Java

@Bean
SecurityFilterChain web(HttpSecurity http) throws Exception {
    http
        // ...
        .httpBasic((basic) -> basic
            .addObjectPostProcessor(new ObjectPostProcessor<BasicAuthenticationFilter>() {
                @Override
                public <O extends BasicAuthenticationFilter> O postProcess(O filter) {
                    filter.setSecurityContextRepository(new HttpSessionSecurityContextRepository());
                    return filter;
                }
            })
        );

    return http.build();
}

以上內容也適用於其他身份驗證機制,例如Bearer Token Authentication

理解顯式儲存要求

在 Spring Security 5 中,預設行為是SecurityContext自動儲存到SecurityContextRepository中,透過SecurityContextPersistenceFilter完成。儲存必須在HttpServletResponse提交之前和SecurityContextPersistenceFilter之前完成。不幸的是,SecurityContext的自動持久化可能會讓使用者感到意外,因為它在請求完成之前(即在提交HttpServletResponse之前)完成。跟蹤狀態以確定是否需要儲存也很複雜,有時會導致不必要的寫入SecurityContextRepository(即HttpSession)。

由於這些原因,SecurityContextPersistenceFilter已被棄用,取而代之的是SecurityContextHolderFilter。在Spring Security 6中,預設行為是SecurityContextHolderFilter只會從SecurityContextRepository中讀取SecurityContext並將其填充到SecurityContextHolder中。現在,如果使用者希望SecurityContext在請求之間持久化,則必須使用SecurityContextRepository顯式儲存SecurityContext。這消除了歧義,並透過僅在必要時才寫入SecurityContextRepository(即HttpSession)來提高效能。

工作原理

總而言之,當requireExplicitSavetrue時,Spring Security 會設定SecurityContextHolderFilter,而不是SecurityContextPersistenceFilter

配置併發會話控制

如果您希望對單個使用者登入應用程式的能力施加限制,Spring Security 透過以下簡單的新增即可提供開箱即用的支援。首先,您需要在配置中新增以下監聽器,以使 Spring Security 瞭解會話生命週期事件

  • Java

  • Kotlin

  • web.xml

@Bean
public HttpSessionEventPublisher httpSessionEventPublisher() {
    return new HttpSessionEventPublisher();
}
@Bean
open fun httpSessionEventPublisher(): HttpSessionEventPublisher {
    return HttpSessionEventPublisher()
}
<listener>
<listener-class>
    org.springframework.security.web.session.HttpSessionEventPublisher
</listener-class>
</listener>

然後將以下行新增到您的安全配置中

  • Java

  • Kotlin

  • XML

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) {
    http
        .sessionManagement((session) -> session
            .maximumSessions(1)
        );
    return http.build();
}
@Bean
open fun filterChain(http: HttpSecurity): SecurityFilterChain {
    http {
        sessionManagement {
            sessionConcurrency {
                maximumSessions = 1
            }
        }
    }
    return http.build()
}
<http>
...
<session-management>
    <concurrency-control max-sessions="1" />
</session-management>
</http>

這將阻止使用者多次登入 - 第二次登入將導致第一次登入失效。

您還可以根據使用者的身份進行調整。例如,管理員可能能夠擁有多個會話

  • Java

  • Kotlin

  • XML

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) {
	AuthorizationManager<?> isAdmin = AuthorityAuthorizationManager.hasRole("ADMIN");
    http
        .sessionManagement((session) -> session
            .maximumSessions((authentication) -> isAdmin.authorize(() -> authentication, null).isGranted() ? -1 : 1)
        );
    return http.build();
}
@Bean
open fun filterChain(http: HttpSecurity): SecurityFilterChain {
    val isAdmin: AuthorizationManager<*> = AuthorityAuthorizationManager.hasRole("ADMIN")
    http {
        sessionManagement {
            sessionConcurrency {
                maximumSessions {
                    authentication -> if (isAdmin.authorize({ authentication }, null)!!.isGranted) -1 else 1
                }
            }
        }
    }
    return http.build()
}
<http>
...
<session-management>
    <concurrency-control max-sessions-ref="sessionLimit" />
</session-management>
</http>

<b:bean id="sessionLimit" class="my.SessionLimitImplementation"/>

使用 Spring Boot,您可以按以下方式測試上述配置

  • Java

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc
public class MaximumSessionsTests {

    @Autowired
    private MockMvc mvc;

    @Test
    void loginOnSecondLoginThenFirstSessionTerminated() throws Exception {
        MvcResult mvcResult = this.mvc.perform(formLogin())
                .andExpect(authenticated())
                .andReturn();

        MockHttpSession firstLoginSession = (MockHttpSession) mvcResult.getRequest().getSession();

        this.mvc.perform(get("/").session(firstLoginSession))
                .andExpect(authenticated());

        this.mvc.perform(formLogin()).andExpect(authenticated());

        // first session is terminated by second login
        this.mvc.perform(get("/").session(firstLoginSession))
                .andExpect(unauthenticated());
    }

}

您可以使用最大會話示例進行嘗試。

通常,您更希望阻止第二次登入,在這種情況下,您可以使用

  • Java

  • Kotlin

  • XML

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) {
    http
        .sessionManagement((session) -> session
            .maximumSessions(1)
            .maxSessionsPreventsLogin(true)
        );
    return http.build();
}
@Bean
open fun filterChain(http: HttpSecurity): SecurityFilterChain {
    http {
        sessionManagement {
            sessionConcurrency {
                maximumSessions = 1
                maxSessionsPreventsLogin = true
            }
        }
    }
    return http.build()
}
<http>
<session-management>
    <concurrency-control max-sessions="1" error-if-maximum-exceeded="true" />
</session-management>
</http>

第二次登入將被拒絕。這裡的“拒絕”是指如果使用基於表單的登入,使用者將被髮送到authentication-failure-url。如果第二次身份驗證是透過其他非互動式機制(例如“記住我”)進行的,則將向客戶端傳送“未授權”(401)錯誤。如果您想使用錯誤頁面,可以將屬性session-authentication-error-url新增到session-management元素中。

使用 Spring Boot,您可以按以下方式測試上述配置

  • Java

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc
public class MaximumSessionsPreventLoginTests {

    @Autowired
    private MockMvc mvc;

    @Test
    void loginOnSecondLoginThenPreventLogin() throws Exception {
        MvcResult mvcResult = this.mvc.perform(formLogin())
                .andExpect(authenticated())
                .andReturn();

        MockHttpSession firstLoginSession = (MockHttpSession) mvcResult.getRequest().getSession();

        this.mvc.perform(get("/").session(firstLoginSession))
                .andExpect(authenticated());

        // second login is prevented
        this.mvc.perform(formLogin()).andExpect(unauthenticated());

        // first session is still valid
        this.mvc.perform(get("/").session(firstLoginSession))
                .andExpect(authenticated());
    }

}

如果您正在使用基於表單登入的自定義身份驗證過濾器,則必須顯式配置併發會話控制支援。您可以使用最大會話阻止登入示例進行嘗試。

如果您正在使用UserDetails的自定義實現,請確保您重寫了equals()hashCode()方法。Spring Security 中的預設SessionRegistry實現依賴於使用這些方法來正確識別和管理使用者會話的記憶體中 Map。未能重寫它們可能會導致會話跟蹤和使用者比較行為異常的問題。

檢測超時

會話會自動過期,無需採取任何措施來確保安全上下文被移除。話雖如此,Spring Security 可以檢測會話何時過期並採取您指定的特定操作。例如,當用戶使用已過期的會話發出請求時,您可能希望重定向到特定的端點。這可以透過HttpSecurity中的invalidSessionUrl實現。

  • Java

  • Kotlin

  • XML

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) {
    http
        .sessionManagement((session) -> session
            .invalidSessionUrl("/invalidSession")
        );
    return http.build();
}
@Bean
open fun filterChain(http: HttpSecurity): SecurityFilterChain {
    http {
        sessionManagement {
            invalidSessionUrl = "/invalidSession"
        }
    }
    return http.build()
}
<http>
...
<session-management invalid-session-url="/invalidSession" />
</http>

請注意,如果您使用此機制來檢測會話超時,如果使用者登出後又在不關閉瀏覽器的情況下重新登入,它可能會錯誤地報告錯誤。這是因為會話無效時不會清除會話 cookie,即使使用者已登出,該 cookie 仍會重新提交。如果出現這種情況,您可能需要配置登出以清除會話 cookie

自定義無效會話策略

invalidSessionUrl是使用SimpleRedirectInvalidSessionStrategy實現設定InvalidSessionStrategy的便捷方法。如果您想自定義行為,可以實現InvalidSessionStrategy介面並透過invalidSessionStrategy方法進行配置。

  • Java

  • Kotlin

  • XML

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) {
    http
        .sessionManagement((session) -> session
            .invalidSessionStrategy(new MyCustomInvalidSessionStrategy())
        );
    return http.build();
}
@Bean
open fun filterChain(http: HttpSecurity): SecurityFilterChain {
    http {
        sessionManagement {
            invalidSessionStrategy = MyCustomInvalidSessionStrategy()
        }
    }
    return http.build()
}
<http>
...
<session-management invalid-session-strategy-ref="myCustomInvalidSessionStrategy" />
<bean name="myCustomInvalidSessionStrategy" class="com.example.MyCustomInvalidSessionStrategy" />
</http>

您可以在登出時明確刪除 JSESSIONID cookie,例如透過在登出處理程式中使用Clear-Site-Data header

  • Java

  • Kotlin

  • XML

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) {
    http
        .logout((logout) -> logout
            .addLogoutHandler(new HeaderWriterLogoutHandler(new ClearSiteDataHeaderWriter(COOKIES)))
        );
    return http.build();
}
@Bean
open fun filterChain(http: HttpSecurity): SecurityFilterChain {
    http {
        logout {
            addLogoutHandler(HeaderWriterLogoutHandler(ClearSiteDataHeaderWriter(COOKIES)))
        }
    }
    return http.build()
}
<http>
<logout success-handler-ref="clearSiteDataHandler" />
<b:bean id="clearSiteDataHandler" class="org.springframework.security.web.authentication.logout.HeaderWriterLogoutHandler">
    <b:constructor-arg>
        <b:bean class="org.springframework.security.web.header.writers.ClearSiteDataHeaderWriter">
            <b:constructor-arg>
                <b:list>
                    <b:value>COOKIES</b:value>
                </b:list>
            </b:constructor-arg>
        </b:bean>
    </b:constructor-arg>
</b:bean>
</http>

這具有與容器無關的優點,並且適用於任何支援Clear-Site-Data頭的容器。

作為替代方案,您還可以在登出處理程式中使用以下語法

  • Java

  • Kotlin

  • XML

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) {
    http
        .logout((logout) -> logout
            .deleteCookies("JSESSIONID")
        );
    return http.build();
}
@Bean
open fun filterChain(http: HttpSecurity): SecurityFilterChain {
    http {
        logout {
            deleteCookies("JSESSIONID")
        }
    }
    return http.build()
}
<http>
  <logout delete-cookies="JSESSIONID" />
</http>

不幸的是,這不能保證適用於每個 servlet 容器,因此您需要在自己的環境中進行測試。

如果您的應用程式在代理伺服器後面執行,您還可以透過配置代理伺服器來刪除會話 cookie。例如,透過使用 Apache HTTPD 的mod_headers,以下指令透過在對登出請求的響應中使其過期來刪除JSESSIONID cookie(假設應用程式部署在/tutorial路徑下)

<LocationMatch "/tutorial/logout">
Header always set Set-Cookie "JSESSIONID=;Path=/tutorial;Expires=Thu, 01 Jan 1970 00:00:00 GMT"
</LocationMatch>

有關清除站點資料登出部分的更多詳細資訊。

理解會話固定攻擊防護

會話固定攻擊是一種潛在的風險,惡意攻擊者可以透過訪問網站建立會話,然後說服另一個使用者使用相同的會話登入(例如,透過向他們傳送包含會話識別符號作為引數的連結)。Spring Security 透過在使用者登入時建立新會話或更改會話 ID 來自動防範此問題。

配置會話固定保護

您可以透過選擇以下三種推薦選項來控制會話固定保護策略

  • changeSessionId - 不建立新會話。相反,使用 Servlet 容器提供的會話固定保護(HttpServletRequest#changeSessionId())。此選項僅在 Servlet 3.1(Java EE 7)及更高版本的容器中可用。在舊版本容器中指定它將導致異常。這是 Servlet 3.1 及更高版本容器中的預設設定。

  • newSession - 建立一個“乾淨”的新會話,不復制現有會話資料(Spring Security 相關屬性仍將被複制)。

  • migrateSession - 建立一個新會話並將所有現有會話屬性複製到新會話。這是 Servlet 3.0 或更早版本容器中的預設設定。

您可以透過以下方式配置會話固定保護

  • Java

  • Kotlin

  • XML

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) {
    http
        .sessionManagement((session) -> session
            .sessionFixation((sessionFixation) -> sessionFixation
                .newSession()
            )
        );
    return http.build();
}
@Bean
open fun filterChain(http: HttpSecurity): SecurityFilterChain {
    http {
        sessionManagement {
            sessionFixation {
                newSession()
            }
        }
    }
    return http.build()
}
<http>
  <session-management session-fixation-protection="newSession" />
</http>

當會話固定保護髮生時,它會導致在應用程式上下文中釋出SessionFixationProtectionEvent。如果您使用changeSessionId,此保護**還會**通知任何jakarta.servlet.http.HttpSessionIdListener,因此如果您的程式碼同時監聽這兩個事件,請謹慎使用。

您還可以將會話固定保護設定為none以停用它,但不建議這樣做,因為它會使您的應用程式容易受到攻擊。

使用SecurityContextHolderStrategy

考慮以下程式碼塊

  • Java

UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
        loginRequest.getUsername(), loginRequest.getPassword());
Authentication authentication = this.authenticationManager.authenticate(token);
// ...
SecurityContext context = SecurityContextHolder.createEmptyContext(); (1)
context.setAuthentication(authentication); (2)
SecurityContextHolder.setContext(context); (3)
  1. 透過靜態訪問SecurityContextHolder建立一個空的SecurityContext例項。

  2. SecurityContext例項中設定Authentication物件。

  3. SecurityContextHolder中靜態設定SecurityContext例項。

雖然上述程式碼工作正常,但它可能會產生一些意想不到的效果:當元件透過SecurityContextHolder靜態訪問SecurityContext時,這可能會在有多個應用程式上下文想要指定SecurityContextHolderStrategy時產生競態條件。這是因為在SecurityContextHolder中,每個類載入器只有一個策略,而不是每個應用程式上下文一個。

為了解決這個問題,元件可以從應用程式上下文連線SecurityContextHolderStrategy。預設情況下,它們仍然會從SecurityContextHolder查詢策略。

這些更改主要是內部的,但它們為應用程式提供了自動裝配SecurityContextHolderStrategy而不是靜態訪問SecurityContext的機會。為此,您應該將程式碼更改為以下內容

  • Java

public class SomeClass {

    private final SecurityContextHolderStrategy securityContextHolderStrategy = SecurityContextHolder.getContextHolderStrategy();

    public void someMethod() {
        UsernamePasswordAuthenticationToken token = UsernamePasswordAuthenticationToken.unauthenticated(
                loginRequest.getUsername(), loginRequest.getPassword());
        Authentication authentication = this.authenticationManager.authenticate(token);
        // ...
        SecurityContext context = this.securityContextHolderStrategy.createEmptyContext(); (1)
        context.setAuthentication(authentication); (2)
        this.securityContextHolderStrategy.setContext(context); (3)
    }

}
  1. 使用已配置的SecurityContextHolderStrategy建立一個空的SecurityContext例項。

  2. SecurityContext例項中設定Authentication物件。

  3. SecurityContextHolderStrategy中設定SecurityContext例項。

強制提前建立會話

有時,提前建立會話可能很有價值。這可以透過使用ForceEagerSessionCreationFilter來實現,其配置方式如下

  • Java

  • Kotlin

  • XML

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) {
    http
        .sessionManagement((session) -> session
            .sessionCreationPolicy(SessionCreationPolicy.ALWAYS)
        );
    return http.build();
}
@Bean
open fun filterChain(http: HttpSecurity): SecurityFilterChain {
    http {
        sessionManagement {
            sessionCreationPolicy = SessionCreationPolicy.ALWAYS
        }
    }
    return http.build()
}
<http create-session="ALWAYS">

</http>

下一步閱讀


1。透過在認證後執行重定向的機制(例如表單登入)進行的認證不會被SessionManagementFilter檢測到,因為在認證請求期間不會呼叫該過濾器。在這些情況下,會話管理功能必須單獨處理。
© . This site is unofficial and not affiliated with VMware.