mirror of https://github.com/halo-dev/halo
Disable CSRF token check for RESTful APIs (#2580)
#### What type of PR is this? /kind bug /area core /milestone 2.0 /kind api-change #### What this PR does / why we need it: 1. Disable CSRF token check for RESTful APIs but login and logout APIs. 2. Enable CORS check for login and logout APIs #### Which issue(s) this PR fixes: Fixes https://github.com/halo-dev/halo/issues/2571 #### How to test? 1. Install a valid theme and create a sample post 2. View the post at theme end 3. Check the response of counter API #### Does this PR introduce a user-facing change? ```release-note 禁用对 RESTful API 的 CSRF 检查 ```pull/2587/head
parent
2505c7fe4a
commit
2527eb42e2
|
@ -7,15 +7,12 @@ import com.nimbusds.jose.JWSAlgorithm;
|
|||
import com.nimbusds.jose.jwk.JWKSet;
|
||||
import com.nimbusds.jose.jwk.RSAKey;
|
||||
import com.nimbusds.jose.jwk.source.ImmutableJWKSet;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
|
||||
import org.springframework.security.config.web.server.ServerHttpSecurity;
|
||||
import org.springframework.security.core.userdetails.ReactiveUserDetailsService;
|
||||
|
@ -27,10 +24,6 @@ import org.springframework.security.oauth2.jwt.NimbusReactiveJwtDecoder;
|
|||
import org.springframework.security.oauth2.jwt.ReactiveJwtDecoder;
|
||||
import org.springframework.security.oauth2.jwt.SupplierReactiveJwtDecoder;
|
||||
import org.springframework.security.web.server.SecurityWebFilterChain;
|
||||
import org.springframework.security.web.server.csrf.CookieServerCsrfTokenRepository;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.cors.reactive.CorsConfigurationSource;
|
||||
import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;
|
||||
import run.halo.app.core.extension.service.RoleService;
|
||||
import run.halo.app.core.extension.service.UserService;
|
||||
import run.halo.app.extension.ReactiveExtensionClient;
|
||||
|
@ -63,10 +56,7 @@ public class WebServerSecurityConfig {
|
|||
RoleService roleService,
|
||||
ObjectProvider<SecurityConfigurer> securityConfigurers) {
|
||||
|
||||
http.csrf().csrfTokenRepository(CookieServerCsrfTokenRepository.withHttpOnlyFalse())
|
||||
.and()
|
||||
.cors(corsSpec -> corsSpec.configurationSource(apiCorsConfigurationSource()))
|
||||
.securityMatcher(pathMatchers("/api/**", "/apis/**", "/login", "/logout"))
|
||||
http.securityMatcher(pathMatchers("/api/**", "/apis/**", "/login", "/logout"))
|
||||
.authorizeExchange(exchanges ->
|
||||
exchanges.anyExchange().access(new RequestInfoAuthorizationManager(roleService)))
|
||||
.anonymous(anonymousSpec -> {
|
||||
|
@ -84,23 +74,6 @@ public class WebServerSecurityConfig {
|
|||
return http.build();
|
||||
}
|
||||
|
||||
CorsConfigurationSource apiCorsConfigurationSource() {
|
||||
CorsConfiguration configuration = new CorsConfiguration();
|
||||
configuration.setAllowedOriginPatterns(List.of("*"));
|
||||
configuration.setAllowedHeaders(
|
||||
List.of(HttpHeaders.AUTHORIZATION, HttpHeaders.CONTENT_TYPE, HttpHeaders.ACCEPT,
|
||||
"X-XSRF-TOKEN", HttpHeaders.COOKIE));
|
||||
configuration.setAllowCredentials(true);
|
||||
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "PATCH"));
|
||||
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
|
||||
source.registerCorsConfiguration("/api/**", configuration);
|
||||
source.registerCorsConfiguration("/apis/**", configuration);
|
||||
// TODO Remove both login and logout path until we provide the console proxy.
|
||||
source.registerCorsConfiguration("/login", configuration);
|
||||
source.registerCorsConfiguration("/logout", configuration);
|
||||
return source;
|
||||
}
|
||||
|
||||
@Bean
|
||||
ReactiveUserDetailsService userDetailsService(UserService userService,
|
||||
RoleService roleService) {
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
package run.halo.app.security;
|
||||
|
||||
import com.google.common.net.HttpHeaders;
|
||||
import java.util.List;
|
||||
import org.springframework.security.config.web.server.ServerHttpSecurity;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.cors.reactive.CorsConfigurationSource;
|
||||
import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;
|
||||
import run.halo.app.security.authentication.SecurityConfigurer;
|
||||
|
||||
@Component
|
||||
public class CorsConfigurer implements SecurityConfigurer {
|
||||
@Override
|
||||
public void configure(ServerHttpSecurity http) {
|
||||
http.cors(spec -> spec.configurationSource(apiCorsConfigSource()));
|
||||
}
|
||||
|
||||
CorsConfigurationSource apiCorsConfigSource() {
|
||||
var configuration = new CorsConfiguration();
|
||||
configuration.setAllowedOriginPatterns(List.of("*"));
|
||||
configuration.setAllowedHeaders(
|
||||
List.of(HttpHeaders.AUTHORIZATION, HttpHeaders.CONTENT_TYPE, HttpHeaders.ACCEPT,
|
||||
"X-XSRF-TOKEN", HttpHeaders.COOKIE));
|
||||
configuration.setAllowCredentials(true);
|
||||
configuration.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "PATCH"));
|
||||
|
||||
var source = new UrlBasedCorsConfigurationSource();
|
||||
source.registerCorsConfiguration("/api/**", configuration);
|
||||
source.registerCorsConfiguration("/apis/**", configuration);
|
||||
return source;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package run.halo.app.security;
|
||||
|
||||
import static org.springframework.security.web.server.util.matcher.ServerWebExchangeMatchers.pathMatchers;
|
||||
|
||||
import org.springframework.security.config.web.server.ServerHttpSecurity;
|
||||
import org.springframework.security.web.server.csrf.CookieServerCsrfTokenRepository;
|
||||
import org.springframework.security.web.server.csrf.CsrfWebFilter;
|
||||
import org.springframework.security.web.server.util.matcher.AndServerWebExchangeMatcher;
|
||||
import org.springframework.security.web.server.util.matcher.NegatedServerWebExchangeMatcher;
|
||||
import org.springframework.stereotype.Component;
|
||||
import run.halo.app.security.authentication.SecurityConfigurer;
|
||||
|
||||
@Component
|
||||
public class CsrfConfigurer implements SecurityConfigurer {
|
||||
|
||||
@Override
|
||||
public void configure(ServerHttpSecurity http) {
|
||||
var csrfMatcher = new AndServerWebExchangeMatcher(
|
||||
CsrfWebFilter.DEFAULT_CSRF_MATCHER,
|
||||
new NegatedServerWebExchangeMatcher(pathMatchers("/api/**", "/apis/**")
|
||||
));
|
||||
|
||||
http.csrf().csrfTokenRepository(CookieServerCsrfTokenRepository.withHttpOnlyFalse())
|
||||
.requireCsrfProtectionMatcher(csrfMatcher);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue