added new controller to handle no static resource error

This commit is contained in:
Dario Ghunney Ware
2025-11-04 12:51:37 +00:00
committed by DarioGii
parent ff577e16f4
commit fa332ec201
5 changed files with 76 additions and 18 deletions

View File

@@ -67,16 +67,15 @@ public class RequestUriUtils {
// Public auth endpoints that don't require authentication
return trimmedUri.startsWith("/login")
|| trimmedUri.startsWith("/signup")
|| trimmedUri.startsWith("/register")
|| trimmedUri.startsWith("/auth/")
|| trimmedUri.startsWith("/oauth2")
|| trimmedUri.startsWith("/saml2")
|| trimmedUri.contains("/login/oauth2/code/") // Spring Security OAuth2 callback
|| trimmedUri.contains("/oauth2/authorization/") // OAuth2 authorization endpoint
|| trimmedUri.startsWith("/api/v1/auth/login")
|| trimmedUri.startsWith("/api/v1/auth/register")
|| trimmedUri.startsWith("/api/v1/auth/refresh")
|| trimmedUri.startsWith("/api/v1/auth/logout")
|| trimmedUri.startsWith("/api/v1/user/register")
|| trimmedUri.startsWith("/api/v1/proprietary/ui-data/account")
|| trimmedUri.startsWith("/api/v1/config")
|| trimmedUri.startsWith("/v1/api-docs")

View File

@@ -0,0 +1,58 @@
package stirling.software.proprietary.controller.web;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* Controller to handle OAuth2 callback routing. Returns an HTML page that preserves the URL
* fragment (which contains the JWT token) and redirects to the frontend.
*/
@Controller
public class ReactRoutingController {
@Value("${frontend.dev.url:http://localhost:5173}")
private String frontendDevUrl;
@Value("${app.dev.mode:true}")
private boolean devMode;
/**
* Handle /auth/callback by returning HTML that preserves the fragment and redirects to the
* frontend.
*/
@GetMapping(value = "/auth/callback", produces = MediaType.TEXT_HTML_VALUE)
@ResponseBody
public String handleAuthCallback() {
String targetUrl = devMode ? frontendDevUrl : "";
return """
<!DOCTYPE html>
<html>
<head>
<title>OAuth Callback</title>
<script>
// Preserve the URL fragment and redirect to the frontend
var targetUrl = '%s';
var fragment = window.location.hash;
if (targetUrl) {
// Development mode - redirect to Vite dev server
window.location.replace(targetUrl + '/auth/callback' + fragment);
} else {
// Production mode - redirect to React route
window.location.replace('/#/auth/callback' + fragment);
}
</script>
</head>
<body>
<div style="text-align: center; margin-top: 50px;">
<p>Completing authentication...</p>
<p>If you are not redirected automatically, <a href="%s">click here</a>.</p>
</div>
</body>
</html>
"""
.formatted(targetUrl, targetUrl.isEmpty() ? "/" : targetUrl);
}
}

View File

@@ -160,7 +160,13 @@ public class SecurityConfiguration {
// Set exposed headers (headers that the browser can access)
cfg.setExposedHeaders(
List.of("WWW-Authenticate", "X-Total-Count", "X-Page-Number", "X-Page-Size"));
List.of(
"WWW-Authenticate",
"X-Total-Count",
"X-Page-Number",
"X-Page-Size",
"Content-Disposition",
"Content-Type"));
// Allow credentials (cookies, authorization headers)
cfg.setAllowCredentials(true);
@@ -181,7 +187,11 @@ public class SecurityConfiguration {
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
public SecurityFilterChain filterChain(
HttpSecurity http,
@Lazy IPRateLimitingFilter rateLimitingFilter,
@Lazy JwtAuthenticationFilter jwtAuthenticationFilter)
throws Exception {
// Enable CORS only if we have configured origins
CorsConfigurationSource corsSource = corsConfigurationSource();
if (corsSource != null) {
@@ -200,9 +210,8 @@ public class SecurityConfiguration {
http.addFilterBefore(
userAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
.addFilterBefore(
rateLimitingFilter(), UsernamePasswordAuthenticationFilter.class)
.addFilterBefore(jwtAuthenticationFilter(), UserAuthenticationFilter.class);
.addFilterBefore(rateLimitingFilter, UsernamePasswordAuthenticationFilter.class)
.addFilterBefore(jwtAuthenticationFilter, UserAuthenticationFilter.class);
if (!securityProperties.getCsrfDisabled()) {
CookieCsrfTokenRepository cookieRepo =
@@ -310,7 +319,8 @@ public class SecurityConfiguration {
// Check if it's a public auth endpoint or static
// resource
return RequestUriUtils.isStaticResource(
contextPath, uri) || RequestUriUtils.isPublicAuthEndpoint(
contextPath, uri)
|| RequestUriUtils.isPublicAuthEndpoint(
uri, contextPath);
})
.permitAll()

View File

@@ -252,11 +252,4 @@ public class AuthController {
return userMap;
}
// ===========================
// Request/Response DTOs
// ===========================
/** Login request DTO */
public record LoginRequest(String email, String password) {}
}

View File

@@ -250,7 +250,6 @@ public class UserAuthenticationFilter extends OncePerRequestFilter {
String contextPath = request.getContextPath();
String[] permitAllPatterns = {
contextPath + "/login",
contextPath + "/signup",
contextPath + "/register",
contextPath + "/error",
contextPath + "/images/",
@@ -262,7 +261,6 @@ public class UserAuthenticationFilter extends OncePerRequestFilter {
contextPath + "/pdfjs-legacy/",
contextPath + "/api/v1/info/status",
contextPath + "/api/v1/auth/login",
contextPath + "/api/v1/auth/register",
contextPath + "/api/v1/auth/refresh",
contextPath + "/api/v1/auth/me",
contextPath + "/site.webmanifest"