Skip to content

Commit c7b613a

Browse files
Step 12 - Secure BFF application
1 parent e21a28c commit c7b613a

File tree

6 files changed

+66
-20
lines changed

6 files changed

+66
-20
lines changed

flights-api/src/main/java/com/example/api/SecurityConfiguration.java

-18
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,13 @@
44

55
import org.springframework.context.annotation.Bean;
66
import org.springframework.context.annotation.Configuration;
7-
import org.springframework.security.config.Customizer;
87
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
98
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
109
import org.springframework.security.config.annotation.web.configurers.oauth2.server.resource.OAuth2ResourceServerConfigurer;
1110
import org.springframework.security.core.authority.AuthorityUtils;
1211
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
1312
import org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter;
1413
import org.springframework.security.web.SecurityFilterChain;
15-
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;
16-
import org.springframework.web.cors.CorsConfiguration;
17-
import org.springframework.web.cors.CorsConfigurationSource;
18-
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
1914

2015
@Configuration
2116
@EnableGlobalMethodSecurity(prePostEnabled = true)
@@ -26,24 +21,11 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http, AccessRuleAuth
2621
// @formatter:off
2722
http
2823
.authorizeHttpRequests((authz) -> authz.anyRequest().access(access))
29-
.cors(Customizer.withDefaults())
3024
.oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt);
3125
// @formatter:on
3226
return http.build();
3327
}
3428

35-
@Bean
36-
CorsConfigurationSource corsConfigurationSource() {
37-
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
38-
CorsConfiguration config = new CorsConfiguration();
39-
config.addAllowedHeader("*");
40-
config.addAllowedMethod("*");
41-
config.addAllowedOrigin("http://127.0.0.1:8000");
42-
config.setAllowCredentials(true);
43-
source.registerCorsConfiguration("/**", config);
44-
return source;
45-
}
46-
4729
@Bean
4830
public JwtAuthenticationConverter jwtAuthenticationConverter() {
4931
JwtGrantedAuthoritiesConverter authoritiesConverter = new JwtGrantedAuthoritiesConverter();

flights-web/build.gradle

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ ext {
1717
}
1818

1919
dependencies {
20+
implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
2021
implementation 'org.springframework.boot:spring-boot-starter-webflux'
2122
implementation 'org.springframework.cloud:spring-cloud-starter-gateway'
2223
testImplementation 'org.springframework.boot:spring-boot-starter-test'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package com.example.web;
2+
3+
import java.time.Duration;
4+
5+
import reactor.core.publisher.Mono;
6+
7+
import org.springframework.boot.autoconfigure.web.reactive.WebFluxProperties;
8+
import org.springframework.http.ResponseCookie;
9+
import org.springframework.security.web.server.csrf.CsrfToken;
10+
import org.springframework.stereotype.Component;
11+
import org.springframework.web.server.ServerWebExchange;
12+
import org.springframework.web.server.WebFilter;
13+
import org.springframework.web.server.WebFilterChain;
14+
15+
@Component
16+
public class CsrfCookieWebFilter implements WebFilter {
17+
18+
@Override
19+
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
20+
String key = CsrfToken.class.getName();
21+
Mono<CsrfToken> csrfToken = null != exchange.getAttribute(key) ? exchange.getAttribute(key) : Mono.empty();
22+
return csrfToken.doOnSuccess(token -> {
23+
ResponseCookie cookie = ResponseCookie.from("XSRF-TOKEN", token.getToken()).maxAge(Duration.ofHours(1))
24+
.httpOnly(false).path("/").sameSite(WebFluxProperties.SameSite.LAX.attribute()).build();
25+
exchange.getResponse().getCookies().add("XSRF-TOKEN", cookie);
26+
}).then(chain.filter(exchange));
27+
}
28+
29+
}
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,28 @@
11
package com.example.web;
22

3+
import org.springframework.context.annotation.Bean;
34
import org.springframework.context.annotation.Configuration;
5+
import org.springframework.security.config.Customizer;
6+
import org.springframework.security.config.web.server.ServerHttpSecurity;
7+
import org.springframework.security.web.server.SecurityWebFilterChain;
8+
import org.springframework.security.web.server.csrf.CookieServerCsrfTokenRepository;
49

510
@Configuration
611
public class SecurityConfiguration {
712

13+
@Bean
14+
SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
15+
// @formatter:off
16+
http
17+
.authorizeExchange((authorize) -> authorize
18+
.anyExchange().authenticated()
19+
)
20+
.oauth2Login(Customizer.withDefaults())
21+
.csrf((csrf) -> csrf
22+
.csrfTokenRepository(CookieServerCsrfTokenRepository.withHttpOnlyFalse())
23+
);
24+
// @formatter:on
25+
return http.build();
26+
}
27+
828
}

flights-web/src/main/resources/application.yml

+15
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,28 @@ logging:
66
org.springframework.security: TRACE
77

88
spring:
9+
security:
10+
oauth2:
11+
client:
12+
registration:
13+
air-traffic-control-client:
14+
provider: spring
15+
client-id: air-traffic-control
16+
client-secret: secret
17+
scope: openid,flights:read,flights:write
18+
client-name: Spring
19+
provider:
20+
spring:
21+
issuer-uri: http://auth-server:9000
922
cloud:
1023
gateway:
1124
routes:
1225
- id: resource
1326
uri: http://localhost:8090
1427
predicates:
1528
- Path=/flights/**, /user/**
29+
filters:
30+
- TokenRelay=
1631
- id: default
1732
uri: forward:/index.html
1833
predicates:

spa/src/app/interceptors/gateway.interceptor.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,7 @@ export class GatewayInterceptor implements HttpInterceptor {
1313
}
1414

1515
const newReq = req.clone({
16-
url: 'http://127.0.0.1:8090' + req.url,
17-
withCredentials: true
16+
url: 'http://127.0.0.1:8000' + req.url
1817
});
1918

2019
return next.handle(newReq);

0 commit comments

Comments
 (0)