mirror of https://github.com/halo-dev/halo
Fix the problem of redirecting to previous URI with fragment after authenticated (#6862)
#### What type of PR is this? /kind bug /area core /milestone 2.20.x #### What this PR does / why we need it: This PR ignores URI fragment while removing redirect URI. Before that, users may be redirected to previous redirect URI that contains fragment. #### Does this PR introduce a user-facing change? ```release-note 修复二次登录后重定向跳转至旧地址的问题 ```pull/6865/head v2.20.1
parent
17eea823a5
commit
dd5f02e505
|
@ -4,6 +4,7 @@ import static org.springframework.security.web.server.util.matcher.ServerWebExch
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.Objects;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.http.HttpMethod;
|
import org.springframework.http.HttpMethod;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
|
@ -58,24 +59,49 @@ public class HaloServerRequestCache extends WebSessionServerRequestCache {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Mono<ServerHttpRequest> removeMatchingRequest(ServerWebExchange exchange) {
|
public Mono<ServerHttpRequest> removeMatchingRequest(ServerWebExchange exchange) {
|
||||||
|
return getRedirectUri(exchange)
|
||||||
|
.flatMap(redirectUri -> {
|
||||||
|
if (redirectUri.getFragment() != null) {
|
||||||
|
var redirectUriInApplication =
|
||||||
|
uriInApplication(exchange.getRequest(), redirectUri, false);
|
||||||
|
var uriInApplication =
|
||||||
|
uriInApplication(exchange.getRequest(), exchange.getRequest().getURI());
|
||||||
|
// compare the path and query only
|
||||||
|
if (!Objects.equals(redirectUriInApplication, uriInApplication)) {
|
||||||
|
return Mono.empty();
|
||||||
|
}
|
||||||
|
// remove the exchange
|
||||||
|
return exchange.getSession().map(WebSession::getAttributes)
|
||||||
|
.doOnNext(attributes -> attributes.remove(this.sessionAttrName))
|
||||||
|
.thenReturn(exchange.getRequest());
|
||||||
|
}
|
||||||
return super.removeMatchingRequest(exchange);
|
return super.removeMatchingRequest(exchange);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private Mono<Void> saveRedirectUri(ServerWebExchange exchange, URI redirectUri) {
|
private Mono<Void> saveRedirectUri(ServerWebExchange exchange, URI redirectUri) {
|
||||||
var requestPath = exchange.getRequest().getPath();
|
var redirectUriInApplication = uriInApplication(exchange.getRequest(), redirectUri);
|
||||||
var redirectPath = RequestPath.parse(redirectUri, requestPath.contextPath().value());
|
|
||||||
var query = redirectUri.getRawQuery();
|
|
||||||
var fragment = redirectUri.getRawFragment();
|
|
||||||
var finalRedirect = redirectPath.pathWithinApplication()
|
|
||||||
+ (query == null ? "" : "?" + query)
|
|
||||||
+ (fragment == null ? "" : "#" + fragment);
|
|
||||||
|
|
||||||
return exchange.getSession()
|
return exchange.getSession()
|
||||||
.map(WebSession::getAttributes)
|
.map(WebSession::getAttributes)
|
||||||
.doOnNext(attributes -> attributes.put(this.sessionAttrName, finalRedirect))
|
.doOnNext(attributes -> attributes.put(this.sessionAttrName, redirectUriInApplication))
|
||||||
.then();
|
.then();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String uriInApplication(ServerHttpRequest request, URI uri) {
|
||||||
|
return uriInApplication(request, uri, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String uriInApplication(
|
||||||
|
ServerHttpRequest request, URI uri, boolean appendFragment
|
||||||
|
) {
|
||||||
|
var path = RequestPath.parse(uri, request.getPath().contextPath().value());
|
||||||
|
var query = uri.getRawQuery();
|
||||||
|
var fragment = uri.getRawFragment();
|
||||||
|
return path.pathWithinApplication().value()
|
||||||
|
+ (query == null ? "" : "?" + query)
|
||||||
|
+ (fragment == null || !appendFragment ? "" : "#" + fragment);
|
||||||
|
}
|
||||||
|
|
||||||
private static ServerWebExchangeMatcher createDefaultRequestMatcher() {
|
private static ServerWebExchangeMatcher createDefaultRequestMatcher() {
|
||||||
var get = pathMatchers(HttpMethod.GET, "/**");
|
var get = pathMatchers(HttpMethod.GET, "/**");
|
||||||
var notFavicon = new NegatedServerWebExchangeMatcher(
|
var notFavicon = new NegatedServerWebExchangeMatcher(
|
||||||
|
|
|
@ -59,9 +59,31 @@ class HaloServerRequestCacheTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void shouldRemoveIfRedirectUriFound() {
|
void shouldRemoveIfRedirectUriFound() {
|
||||||
|
var sessionManager = new DefaultWebSessionManager();
|
||||||
|
var mockExchange = MockServerWebExchange.builder(MockServerHttpRequest.get("/login")
|
||||||
|
.queryParam("redirect_uri", "/halo")
|
||||||
|
)
|
||||||
|
.sessionManager(sessionManager)
|
||||||
|
.build();
|
||||||
|
var removeExchange = mockExchange.mutate()
|
||||||
|
.request(builder -> builder.uri(URI.create("/halo")))
|
||||||
|
.build();
|
||||||
|
requestCache.saveRequest(mockExchange)
|
||||||
|
.then(Mono.defer(() -> requestCache.removeMatchingRequest(removeExchange)))
|
||||||
|
.as(StepVerifier::create)
|
||||||
|
.assertNext(request -> {
|
||||||
|
Assertions.assertEquals(URI.create("/halo"), request.getURI());
|
||||||
|
})
|
||||||
|
.verifyComplete();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldRemoveIfRedirectUriFoundAndContainsFragment() {
|
||||||
var sessionManager = new DefaultWebSessionManager();
|
var sessionManager = new DefaultWebSessionManager();
|
||||||
var mockExchange =
|
var mockExchange =
|
||||||
MockServerWebExchange.builder(MockServerHttpRequest.get("/login?redirect_uri=/halo"))
|
MockServerWebExchange.builder(MockServerHttpRequest.get("/login")
|
||||||
|
.queryParam("redirect_uri", "/halo#fragment")
|
||||||
|
)
|
||||||
.sessionManager(sessionManager)
|
.sessionManager(sessionManager)
|
||||||
.build();
|
.build();
|
||||||
var removeExchange = mockExchange.mutate()
|
var removeExchange = mockExchange.mutate()
|
||||||
|
|
Loading…
Reference in New Issue