Skip to content

Commit dd5f02e

Browse files
authored
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 修复二次登录后重定向跳转至旧地址的问题 ```
1 parent 17eea82 commit dd5f02e

File tree

2 files changed

+59
-11
lines changed

2 files changed

+59
-11
lines changed

application/src/main/java/run/halo/app/security/HaloServerRequestCache.java

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import java.net.URI;
66
import java.util.Collections;
7+
import java.util.Objects;
78
import org.apache.commons.lang3.StringUtils;
89
import org.springframework.http.HttpMethod;
910
import org.springframework.http.MediaType;
@@ -58,24 +59,49 @@ public Mono<URI> getRedirectUri(ServerWebExchange exchange) {
5859

5960
@Override
6061
public Mono<ServerHttpRequest> removeMatchingRequest(ServerWebExchange exchange) {
61-
return super.removeMatchingRequest(exchange);
62+
return getRedirectUri(exchange)
63+
.flatMap(redirectUri -> {
64+
if (redirectUri.getFragment() != null) {
65+
var redirectUriInApplication =
66+
uriInApplication(exchange.getRequest(), redirectUri, false);
67+
var uriInApplication =
68+
uriInApplication(exchange.getRequest(), exchange.getRequest().getURI());
69+
// compare the path and query only
70+
if (!Objects.equals(redirectUriInApplication, uriInApplication)) {
71+
return Mono.empty();
72+
}
73+
// remove the exchange
74+
return exchange.getSession().map(WebSession::getAttributes)
75+
.doOnNext(attributes -> attributes.remove(this.sessionAttrName))
76+
.thenReturn(exchange.getRequest());
77+
}
78+
return super.removeMatchingRequest(exchange);
79+
});
6280
}
6381

6482
private Mono<Void> saveRedirectUri(ServerWebExchange exchange, URI redirectUri) {
65-
var requestPath = exchange.getRequest().getPath();
66-
var redirectPath = RequestPath.parse(redirectUri, requestPath.contextPath().value());
67-
var query = redirectUri.getRawQuery();
68-
var fragment = redirectUri.getRawFragment();
69-
var finalRedirect = redirectPath.pathWithinApplication()
70-
+ (query == null ? "" : "?" + query)
71-
+ (fragment == null ? "" : "#" + fragment);
72-
83+
var redirectUriInApplication = uriInApplication(exchange.getRequest(), redirectUri);
7384
return exchange.getSession()
7485
.map(WebSession::getAttributes)
75-
.doOnNext(attributes -> attributes.put(this.sessionAttrName, finalRedirect))
86+
.doOnNext(attributes -> attributes.put(this.sessionAttrName, redirectUriInApplication))
7687
.then();
7788
}
7889

90+
private static String uriInApplication(ServerHttpRequest request, URI uri) {
91+
return uriInApplication(request, uri, true);
92+
}
93+
94+
private static String uriInApplication(
95+
ServerHttpRequest request, URI uri, boolean appendFragment
96+
) {
97+
var path = RequestPath.parse(uri, request.getPath().contextPath().value());
98+
var query = uri.getRawQuery();
99+
var fragment = uri.getRawFragment();
100+
return path.pathWithinApplication().value()
101+
+ (query == null ? "" : "?" + query)
102+
+ (fragment == null || !appendFragment ? "" : "#" + fragment);
103+
}
104+
79105
private static ServerWebExchangeMatcher createDefaultRequestMatcher() {
80106
var get = pathMatchers(HttpMethod.GET, "/**");
81107
var notFavicon = new NegatedServerWebExchangeMatcher(

application/src/test/java/run/halo/app/security/HaloServerRequestCacheTest.java

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,31 @@ void shouldSaveIfRedirectUriPresent() {
5959

6060
@Test
6161
void shouldRemoveIfRedirectUriFound() {
62+
var sessionManager = new DefaultWebSessionManager();
63+
var mockExchange = MockServerWebExchange.builder(MockServerHttpRequest.get("/login")
64+
.queryParam("redirect_uri", "/halo")
65+
)
66+
.sessionManager(sessionManager)
67+
.build();
68+
var removeExchange = mockExchange.mutate()
69+
.request(builder -> builder.uri(URI.create("/halo")))
70+
.build();
71+
requestCache.saveRequest(mockExchange)
72+
.then(Mono.defer(() -> requestCache.removeMatchingRequest(removeExchange)))
73+
.as(StepVerifier::create)
74+
.assertNext(request -> {
75+
Assertions.assertEquals(URI.create("/halo"), request.getURI());
76+
})
77+
.verifyComplete();
78+
}
79+
80+
@Test
81+
void shouldRemoveIfRedirectUriFoundAndContainsFragment() {
6282
var sessionManager = new DefaultWebSessionManager();
6383
var mockExchange =
64-
MockServerWebExchange.builder(MockServerHttpRequest.get("/login?redirect_uri=/halo"))
84+
MockServerWebExchange.builder(MockServerHttpRequest.get("/login")
85+
.queryParam("redirect_uri", "/halo#fragment")
86+
)
6587
.sessionManager(sessionManager)
6688
.build();
6789
var removeExchange = mockExchange.mutate()

0 commit comments

Comments
 (0)