Skip to content

Commit eae23e2

Browse files
committed
Fixed login page renderer
1 parent f65874a commit eae23e2

File tree

6 files changed

+78
-5
lines changed

6 files changed

+78
-5
lines changed

.java-version

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
21

api/src/main/java/io/kafbat/ui/config/auth/AbstractAuthSecurityConfig.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,12 @@ protected AbstractAuthSecurityConfig() {
1919
"/logout",
2020
"/oauth2/**",
2121
"/static/**",
22-
"/api/config/authentication"
22+
"/api/config/authentication",
23+
"/index.html",
24+
"/assets/**",
25+
"/manifest.json",
26+
"/favicon/**",
27+
"/api/authorization"
2328
};
2429

2530
}

api/src/main/java/io/kafbat/ui/config/auth/OAuthSecurityConfig.java

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import io.kafbat.ui.config.auth.logout.OAuthLogoutSuccessHandler;
44
import io.kafbat.ui.service.rbac.AccessControlService;
55
import io.kafbat.ui.service.rbac.extractor.ProviderAuthorityExtractor;
6+
import io.kafbat.ui.util.StaticFileWebFilter;
67
import java.util.ArrayList;
78
import java.util.List;
89
import java.util.Map;
@@ -16,9 +17,11 @@
1617
import org.springframework.boot.context.properties.EnableConfigurationProperties;
1718
import org.springframework.context.annotation.Bean;
1819
import org.springframework.context.annotation.Configuration;
20+
import org.springframework.core.io.ClassPathResource;
1921
import org.springframework.security.config.Customizer;
2022
import org.springframework.security.config.annotation.method.configuration.EnableReactiveMethodSecurity;
2123
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
24+
import org.springframework.security.config.web.server.SecurityWebFiltersOrder;
2225
import org.springframework.security.config.web.server.ServerHttpSecurity;
2326
import org.springframework.security.oauth2.client.oidc.userinfo.OidcReactiveOAuth2UserService;
2427
import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserRequest;
@@ -50,16 +53,22 @@ public class OAuthSecurityConfig extends AbstractAuthSecurityConfig {
5053
public SecurityWebFilterChain configure(ServerHttpSecurity http, OAuthLogoutSuccessHandler logoutHandler) {
5154
log.info("Configuring OAUTH2 authentication.");
5255

53-
return http.authorizeExchange(spec -> spec
56+
ServerHttpSecurity builder = http.authorizeExchange(spec -> spec
5457
.pathMatchers(AUTH_WHITELIST)
5558
.permitAll()
5659
.anyExchange()
5760
.authenticated()
5861
)
5962
.oauth2Login(Customizer.withDefaults())
6063
.logout(spec -> spec.logoutSuccessHandler(logoutHandler))
61-
.csrf(ServerHttpSecurity.CsrfSpec::disable)
62-
.build();
64+
.csrf(ServerHttpSecurity.CsrfSpec::disable);
65+
66+
67+
builder.addFilterAt(new StaticFileWebFilter(
68+
"/login", new ClassPathResource("/static/index.html")
69+
), SecurityWebFiltersOrder.LOGIN_PAGE_GENERATING);
70+
71+
return builder.build();
6372
}
6473

6574
@Bean

api/src/main/java/io/kafbat/ui/controller/AuthenticationController.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import java.nio.charset.Charset;
44
import lombok.RequiredArgsConstructor;
55
import lombok.extern.slf4j.Slf4j;
6+
import org.springframework.core.io.ClassPathResource;
67
import org.springframework.security.web.server.csrf.CsrfToken;
78
import org.springframework.util.MultiValueMap;
89
import org.springframework.web.bind.annotation.GetMapping;
@@ -15,6 +16,11 @@
1516
@Slf4j
1617
public class AuthenticationController {
1718

19+
@GetMapping(value = "/login", produces = {"text/html"})
20+
public Mono<ClassPathResource> getLoginPage(ServerWebExchange exchange) {
21+
return Mono.just(new ClassPathResource("static/index.html"));
22+
}
23+
1824
@GetMapping(value = "/auth", produces = {"text/html"})
1925
public Mono<byte[]> getAuth(ServerWebExchange exchange) {
2026
Mono<CsrfToken> token = exchange.getAttributeOrDefault(CsrfToken.class.getName(), Mono.empty());
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package io.kafbat.ui.util;
2+
3+
import java.io.IOException;
4+
import java.io.InputStream;
5+
import org.springframework.core.io.ClassPathResource;
6+
import org.springframework.core.io.buffer.DataBufferFactory;
7+
import org.springframework.http.HttpMethod;
8+
import org.springframework.http.HttpStatus;
9+
import org.springframework.http.MediaType;
10+
import org.springframework.http.server.reactive.ServerHttpResponse;
11+
import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher;
12+
import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatchers;
13+
import org.springframework.web.server.ServerWebExchange;
14+
import org.springframework.web.server.WebFilter;
15+
import org.springframework.web.server.WebFilterChain;
16+
import reactor.core.publisher.Mono;
17+
18+
public class StaticFileWebFilter implements WebFilter {
19+
private ServerWebExchangeMatcher matcher;
20+
private String contents;
21+
22+
public StaticFileWebFilter(String path, ClassPathResource resource) {
23+
this.matcher = ServerWebExchangeMatchers.pathMatchers(HttpMethod.GET, path);
24+
try (InputStream inputStream = resource.getInputStream()) {
25+
this.contents = ResourceUtil.readAsString(resource);
26+
} catch (IOException e) {
27+
throw new RuntimeException(e);
28+
}
29+
}
30+
31+
@Override
32+
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
33+
return this.matcher.matches(exchange)
34+
.filter(ServerWebExchangeMatcher.MatchResult::isMatch)
35+
.switchIfEmpty(chain.filter(exchange).then(Mono.empty()))
36+
.flatMap((matchResult) -> this.render(exchange));
37+
}
38+
39+
private Mono<Void> render(ServerWebExchange exchange) {
40+
String contextPath = exchange.getRequest().getPath().contextPath().value();
41+
String contentBody = contents
42+
.replace("\"assets/", "\"" + contextPath + "/assets/")
43+
.replace("PUBLIC-PATH-VARIABLE", contextPath);
44+
45+
ServerHttpResponse result = exchange.getResponse();
46+
result.setStatusCode(HttpStatus.OK);
47+
result.getHeaders().setContentType(MediaType.TEXT_HTML);
48+
DataBufferFactory bufferFactory = exchange.getResponse().bufferFactory();
49+
return result.writeWith(Mono.just(bufferFactory.wrap(contentBody.getBytes())));
50+
}
51+
52+
}

frontend/src/components/App.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ const queryClient = new QueryClient({
5050
});
5151
const App: React.FC = () => {
5252
const { isDarkMode } = useContext(ThemeModeContext);
53-
const isAuthRoute = useMatch('/auth/*');
53+
const isAuthRoute = useMatch('/login');
5454

5555
return (
5656
<QueryClientProvider client={queryClient}>

0 commit comments

Comments
 (0)