mirror of
https://github.com/iflytek/skillhub.git
synced 2026-10-09 03:17:52 +00:00
refactor(auth): centralize deployment path resolution
This commit is contained in:
parent
34f244e7a4
commit
647d7271a5
4 changed files with 42 additions and 14 deletions
|
|
@ -1,5 +1,6 @@
|
|||
package com.iflytek.skillhub.compat;
|
||||
|
||||
import com.iflytek.skillhub.auth.oauth.OAuthLoginRedirectSupport;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
|
@ -11,14 +12,8 @@ import java.util.Map;
|
|||
*/
|
||||
@RestController
|
||||
public class WellKnownController {
|
||||
|
||||
@GetMapping("/.well-known/clawhub.json")
|
||||
public Map<String, String> clawhubConfig(HttpServletRequest request) {
|
||||
// Honor the deployment sub-path so CLI clients discover /<prefix>/api/v1 instead of
|
||||
// the domain-root /api/v1. With forward-headers-strategy=framework, an upstream
|
||||
// X-Forwarded-Prefix is reflected into the request context path.
|
||||
String contextPath = request.getContextPath();
|
||||
String prefix = (contextPath == null) ? "" : contextPath;
|
||||
return Map.of("apiBase", prefix + "/api/v1");
|
||||
return Map.of("apiBase", OAuthLoginRedirectSupport.apiBase(request));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import com.iflytek.skillhub.auth.oauth.CustomOAuth2UserService;
|
|||
import com.iflytek.skillhub.auth.oauth.CustomOidcUserService;
|
||||
import com.iflytek.skillhub.auth.oauth.OAuth2LoginFailureHandler;
|
||||
import com.iflytek.skillhub.auth.oauth.OAuth2LoginSuccessHandler;
|
||||
import com.iflytek.skillhub.auth.oauth.OAuthLoginRedirectSupport;
|
||||
import com.iflytek.skillhub.auth.oauth.SkillHubOAuth2AuthorizationRequestResolver;
|
||||
import com.iflytek.skillhub.auth.mock.MockAuthFilter;
|
||||
import com.iflytek.skillhub.auth.policy.RouteSecurityPolicyRegistry;
|
||||
|
|
@ -152,12 +153,8 @@ public class SecurityConfig {
|
|||
)
|
||||
.logout(logout -> logout
|
||||
.logoutUrl("/api/v1/auth/logout")
|
||||
// Redirect to the deployment root honoring any sub-path prefix (X-Forwarded-Prefix
|
||||
// is reflected into the context path), so logout does not escape a sub-path deployment.
|
||||
.logoutSuccessHandler((request, response, authentication) -> {
|
||||
String contextPath = request.getContextPath();
|
||||
response.sendRedirect(((contextPath == null) ? "" : contextPath) + "/");
|
||||
})
|
||||
.logoutSuccessHandler((request, response, authentication) ->
|
||||
response.sendRedirect(OAuthLoginRedirectSupport.webRoot(request)))
|
||||
.invalidateHttpSession(true)
|
||||
.deleteCookies("SESSION")
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
package com.iflytek.skillhub.auth.oauth;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* Utility methods and constants for safely handling post-login redirect targets in OAuth flows.
|
||||
* Utility methods and constants for safely handling OAuth redirect targets and
|
||||
* deployment-path aware browser-visible URLs.
|
||||
*/
|
||||
public final class OAuthLoginRedirectSupport {
|
||||
|
||||
|
|
@ -11,6 +14,30 @@ public final class OAuthLoginRedirectSupport {
|
|||
private OAuthLoginRedirectSupport() {
|
||||
}
|
||||
|
||||
public static String apiBase(HttpServletRequest request) {
|
||||
return deploymentPrefix(request) + "/api/v1";
|
||||
}
|
||||
|
||||
public static String webRoot(HttpServletRequest request) {
|
||||
return deploymentPrefix(request) + "/";
|
||||
}
|
||||
|
||||
static String deploymentPrefix(HttpServletRequest request) {
|
||||
if (request == null) {
|
||||
return "";
|
||||
}
|
||||
String rawPrefix = request.getContextPath();
|
||||
if (rawPrefix == null || rawPrefix.isBlank() || "/".equals(rawPrefix)) {
|
||||
return "";
|
||||
}
|
||||
String prefix = rawPrefix.endsWith("/") ? rawPrefix.substring(0, rawPrefix.length() - 1) : rawPrefix;
|
||||
if (!prefix.startsWith("/") || prefix.contains("//") || prefix.contains("\\")
|
||||
|| prefix.contains("?") || prefix.contains("#")) {
|
||||
return "";
|
||||
}
|
||||
return prefix;
|
||||
}
|
||||
|
||||
public static String sanitizeReturnTo(String candidate) {
|
||||
if (candidate == null || candidate.isBlank()) {
|
||||
return null;
|
||||
|
|
|
|||
|
|
@ -108,6 +108,15 @@ class OAuth2LoginHandlersTest {
|
|||
assertThat(response.getRedirectedUrl()).isEqualTo("/skillhub/dashboard/publish");
|
||||
}
|
||||
|
||||
@Test
|
||||
void deploymentPathSupport_returnsPrefixedApiAndWebRoot() {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setContextPath("/skillhub");
|
||||
|
||||
assertThat(OAuthLoginRedirectSupport.apiBase(request)).isEqualTo("/skillhub/api/v1");
|
||||
assertThat(OAuthLoginRedirectSupport.webRoot(request)).isEqualTo("/skillhub/");
|
||||
}
|
||||
|
||||
/**
|
||||
* Regression test: when an unauthenticated client hits a protected API endpoint, Spring Security
|
||||
* caches that request. With {@code SavedRequestAwareAuthenticationSuccessHandler} the post-login
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue