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
```
pull/6265/head^2
John Niang 2024-07-09 22:07:24 +08:00 committed by GitHub
parent 9cdd8a5301
commit 45d0a475b5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 20 additions and 43 deletions

View File

@ -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<Void> 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));
}
}

View File

@ -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);
}
}