From 45d0a475b507024f9f3ee7944b7794feef2a982c Mon Sep 17 00:00:00 2001 From: John Niang Date: Tue, 9 Jul 2024 22:07:24 +0800 Subject: [PATCH] Use AuthenticationWebFilter for remember-me mechanism (#6298) #### What type of PR is this? /kind cleanup /area core /milestone 2.18.x #### What this PR does / why we need it: This PR simplifies RememberMeAuthenticationFilter by reusing AuthenticationWebFilter. #### Does this PR introduce a user-facing change? ```release-note None ``` --- .../RememberMeAuthenticationFilter.java | 36 ------------------- .../rememberme/RememberMeConfigurer.java | 27 ++++++++++---- 2 files changed, 20 insertions(+), 43 deletions(-) delete mode 100644 application/src/main/java/run/halo/app/security/authentication/rememberme/RememberMeAuthenticationFilter.java diff --git a/application/src/main/java/run/halo/app/security/authentication/rememberme/RememberMeAuthenticationFilter.java b/application/src/main/java/run/halo/app/security/authentication/rememberme/RememberMeAuthenticationFilter.java deleted file mode 100644 index e11d2356f..000000000 --- a/application/src/main/java/run/halo/app/security/authentication/rememberme/RememberMeAuthenticationFilter.java +++ /dev/null @@ -1,36 +0,0 @@ -package run.halo.app.security.authentication.rememberme; - -import lombok.RequiredArgsConstructor; -import org.springframework.lang.NonNull; -import org.springframework.security.core.AuthenticationException; -import org.springframework.security.core.context.SecurityContextImpl; -import org.springframework.security.web.server.context.ServerSecurityContextRepository; -import org.springframework.web.server.ServerWebExchange; -import org.springframework.web.server.WebFilter; -import org.springframework.web.server.WebFilterChain; -import reactor.core.publisher.Mono; - -@RequiredArgsConstructor -public class RememberMeAuthenticationFilter implements WebFilter { - private final ServerSecurityContextRepository securityContextRepository; - private final RememberMeServices rememberMeServices; - private final RememberMeAuthenticationManager rememberMeAuthenticationManager; - - @Override - @NonNull - public Mono filter(@NonNull ServerWebExchange exchange, @NonNull WebFilterChain chain) { - return securityContextRepository.load(exchange) - .switchIfEmpty(Mono.defer(() -> rememberMeServices.autoLogin(exchange) - .flatMap(rememberMeAuthenticationManager::authenticate) - .flatMap(authentication -> { - var securityContext = new SecurityContextImpl(authentication); - return securityContextRepository.save(exchange, securityContext); - }) - .onErrorResume(AuthenticationException.class, - e -> rememberMeServices.loginFail(exchange) - ) - .then(Mono.empty()) - )) - .then(chain.filter(exchange)); - } -} diff --git a/application/src/main/java/run/halo/app/security/authentication/rememberme/RememberMeConfigurer.java b/application/src/main/java/run/halo/app/security/authentication/rememberme/RememberMeConfigurer.java index 57d7a03bf..97cbc683c 100644 --- a/application/src/main/java/run/halo/app/security/authentication/rememberme/RememberMeConfigurer.java +++ b/application/src/main/java/run/halo/app/security/authentication/rememberme/RememberMeConfigurer.java @@ -1,8 +1,12 @@ package run.halo.app.security.authentication.rememberme; +import static org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher.MatchResult; + import lombok.RequiredArgsConstructor; import org.springframework.security.config.web.server.SecurityWebFiltersOrder; import org.springframework.security.config.web.server.ServerHttpSecurity; +import org.springframework.security.core.context.ReactiveSecurityContextHolder; +import org.springframework.security.web.server.authentication.AuthenticationWebFilter; import org.springframework.security.web.server.context.ServerSecurityContextRepository; import org.springframework.stereotype.Component; import run.halo.app.security.authentication.SecurityConfigurer; @@ -10,19 +14,28 @@ import run.halo.app.security.authentication.SecurityConfigurer; @Component @RequiredArgsConstructor public class RememberMeConfigurer implements SecurityConfigurer { + private final RememberMeServices rememberMeServices; + private final ServerSecurityContextRepository securityContextRepository; + private final CookieSignatureKeyResolver cookieSignatureKeyResolver; @Override public void configure(ServerHttpSecurity http) { - http.addFilterAt( - new RememberMeAuthenticationFilter(securityContextRepository, - rememberMeServices, authenticationManager()), - SecurityWebFiltersOrder.AUTHENTICATION); + var authManager = new RememberMeAuthenticationManager(cookieSignatureKeyResolver); + var filter = new AuthenticationWebFilter(authManager); + filter.setSecurityContextRepository(securityContextRepository); + filter.setAuthenticationFailureHandler( + (exchange, exception) -> rememberMeServices.loginFail(exchange.getExchange()) + ); + filter.setServerAuthenticationConverter(rememberMeServices::autoLogin); + filter.setRequiresAuthenticationMatcher( + exchange -> ReactiveSecurityContextHolder.getContext() + .flatMap(securityContext -> MatchResult.notMatch()) + .switchIfEmpty(MatchResult.match()) + ); + http.addFilterAt(filter, SecurityWebFiltersOrder.AUTHENTICATION); } - RememberMeAuthenticationManager authenticationManager() { - return new RememberMeAuthenticationManager(cookieSignatureKeyResolver); - } }