对于最新的稳定版本,请使用 Spring Security 6.5.3spring-doc.cadn.net.cn

响应式迁移

如果您已经为 Reactive 应用程序执行了初始迁移步骤,那么现在可以执行特定于 Reactive 应用程序的步骤。spring-doc.cadn.net.cn

漏洞利用保护迁移

以下步骤与如何配置 CSRF 的更改有关。spring-doc.cadn.net.cn

配置tokenFromMultipartDataEnabled

在 Spring Security 5.8 中,方法tokenFromMultipartDataEnabled被弃用,取而代之的是ServerCsrfTokenRequestAttributeHandler#setTokenFromMultipartDataEnabled.spring-doc.cadn.net.cn

为了解决弃用问题,请执行以下代码:spring-doc.cadn.net.cn

配置tokenFromMultipartDataEnabled带 DSL
@Bean
SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
	http
		// ...
		.csrf((csrf) -> csrf
			.tokenFromMultipartDataEnabled(true)
		);
	return http.build();
}
@Bean
open fun securityWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
	return http {
		// ...
		csrf {
			tokenFromMultipartDataEnabled = true
		}
	}
}

可以替换为:spring-doc.cadn.net.cn

配置tokenFromMultipartDataEnabledServerCsrfTokenRequestAttributeHandler
@Bean
SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
	ServerCsrfTokenRequestAttributeHandler requestHandler = new ServerCsrfTokenRequestAttributeHandler();
	requestHandler.setTokenFromMultipartDataEnabled(true);
	http
		// ...
		.csrf((csrf) -> csrf
			.csrfTokenRequestHandler(requestHandler)
		);
	return http.build();
}
@Bean
open fun securityWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
	val requestHandler = ServerCsrfTokenRequestAttributeHandler()
	requestHandler.tokenFromMultipartDataEnabled = true
	return http {
		// ...
		csrf {
			csrfTokenRequestHandler = requestHandler
		}
	}
}

防止 CSRF BREACH

您可以选择 Spring Security 6 对 BREACH 保护的默认支持CsrfToken使用以下配置:spring-doc.cadn.net.cn

CsrfTokenBREACH 保护
@Bean
SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
	XorServerCsrfTokenRequestAttributeHandler requestHandler = new XorServerCsrfTokenRequestAttributeHandler();
	// ...
	http
		// ...
		.csrf((csrf) -> csrf
			.csrfTokenRequestHandler(requestHandler)
		);
	return http.build();
}
@Bean
open fun securityWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
	val requestHandler = XorServerCsrfTokenRequestAttributeHandler()
	// ...
	return http {
		// ...
		csrf {
			csrfTokenRequestHandler = requestHandler
		}
	}
}

选择退出步骤

如果配置 CSRF BREACH 保护给您带来麻烦,请查看以下方案以获得最佳选择退出行为:spring-doc.cadn.net.cn

我正在使用 AngularJS 或其他 Javascript 框架

如果您使用 AngularJS 和 HttpClientXsrfModule(或其他框架中的类似模块)以及CookieServerCsrfTokenRepository.withHttpOnlyFalse(),您可能会发现自动支持不再有效。spring-doc.cadn.net.cn

在这种情况下,您可以配置 Spring Security 来验证原始CsrfToken从 cookie 中获取,同时使用自定义ServerCsrfTokenRequestHandler与委托,如下所示:spring-doc.cadn.net.cn

配置CsrfTokenBREACH 保护来验证原始Tokens
@Bean
SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
	CookieServerCsrfTokenRepository tokenRepository = CookieServerCsrfTokenRepository.withHttpOnlyFalse();
	XorServerCsrfTokenRequestAttributeHandler delegate = new XorServerCsrfTokenRequestAttributeHandler();
	// Use only the handle() method of XorServerCsrfTokenRequestAttributeHandler and the
	// default implementation of resolveCsrfTokenValue() from ServerCsrfTokenRequestHandler
	ServerCsrfTokenRequestHandler requestHandler = delegate::handle;
	http
		// ...
		.csrf((csrf) -> csrf
			.csrfTokenRepository(tokenRepository)
			.csrfTokenRequestHandler(requestHandler)
		);

	return http.build();
}

@Bean
WebFilter csrfCookieWebFilter() {
	return (exchange, chain) -> {
		Mono<CsrfToken> csrfToken = exchange.getAttributeOrDefault(CsrfToken.class.getName(), Mono.empty());
		return csrfToken.doOnSuccess(token -> {
			/* Ensures the token is subscribed to. */
		}).then(chain.filter(exchange));
	};
}
@Bean
open fun securityWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
	val tokenRepository = CookieServerCsrfTokenRepository.withHttpOnlyFalse()
	val delegate = XorServerCsrfTokenRequestAttributeHandler()
	// Use only the handle() method of XorServerCsrfTokenRequestAttributeHandler and the
	// default implementation of resolveCsrfTokenValue() from ServerCsrfTokenRequestHandler
	val requestHandler = ServerCsrfTokenRequestHandler(delegate::handle)
	return http.invoke {
		// ...
		csrf {
			csrfTokenRepository = tokenRepository
			csrfTokenRequestHandler = requestHandler
		}
	}
}

@Bean
fun csrfCookieWebFilter(): WebFilter {
	return WebFilter { exchange, chain ->
		val csrfToken = exchange.getAttribute<Mono<CsrfToken>>(CsrfToken::class.java.name) ?: Mono.empty()
		csrfToken.doOnSuccess {
            /* Ensures the token is subscribed to. */
		}.then(chain.filter(exchange))
	}
}

出于其他原因,我需要选择退出 CSRF BREACH 保护

如果 CSRF BREACH 保护由于其他原因不适合您,您可以使用以下配置选择退出:spring-doc.cadn.net.cn

选择退出CsrfTokenBREACH 保护
@Bean
SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
	ServerCsrfTokenRequestAttributeHandler requestHandler = new ServerCsrfTokenRequestAttributeHandler();
	http
		// ...
		.csrf((csrf) -> csrf
			.csrfTokenRequestHandler(requestHandler)
		);
	return http.build();
}
@Bean
open fun securityWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
	val requestHandler = ServerCsrfTokenRequestAttributeHandler()
	return http {
		// ...
		csrf {
			csrfTokenRequestHandler = requestHandler
		}
	}
}

AuthorizationManager用于方法安全性

如果您在进行这些更改时遇到问题,可以按照本节末尾的选择退出步骤进行作。spring-doc.cadn.net.cn

在 Spring Security 5.8 中,useAuthorizationManager被添加到@EnableReactiveMethodSecurity以允许应用程序选择加入AuthorizationManager的特点。spring-doc.cadn.net.cn

改变useAuthorizationManagertrue

要选择加入,请更改useAuthorizationManagertrue这样:spring-doc.cadn.net.cn

@EnableReactiveMethodSecurity
@EnableReactiveMethodSecurity
@EnableReactiveMethodSecurity(useAuthorizationManager = true)
@EnableReactiveMethodSecurity(useAuthorizationManager = true)

检查AnnotationConfigurationExceptions

useAuthorizationManager激活对 Spring Security 的不可重复或其他不兼容的注释的更严格的强制执行。如果在打开后useAuthorizationManager你看AnnotationConfigurationException,请按照异常消息中的说明清理应用程序的方法安全注释用法。spring-doc.cadn.net.cn

选择退出步骤

如果您遇到麻烦AuthorizationManager对于响应式方法安全性,您可以通过更改以下内容来选择退出:spring-doc.cadn.net.cn

@EnableReactiveMethodSecurity
@EnableReactiveMethodSecurity
@EnableReactiveMethodSecurity(useAuthorizationManager = false)
@EnableReactiveMethodSecurity(useAuthorizationManager = false)

传播AuthenticationServiceExceptions

AuthenticationFilter传播AuthenticationServiceExceptions 到ServerAuthenticationEntryPoint. 因为AuthenticationServiceExceptions 表示服务器端错误而不是客户端错误,在 6.0 中,这会更改以将它们传播到容器。spring-doc.cadn.net.cn

配置ServerAuthenticationFailureHandler重新投掷AuthenticationServiceExceptions

要为 6.0 默认设置做准备,httpBasicoauth2ResourceServer应配置为 rethrowAuthenticationServiceExceptions.spring-doc.cadn.net.cn

对于每个,为httpBasicoauth2ResourceServer:spring-doc.cadn.net.cn

ServerAuthenticationEntryPoint bearerEntryPoint = new BearerTokenServerAuthenticationEntryPoint();
ServerAuthenticationEntryPoint basicEntryPoint = new HttpStatusServerEntryPoint(HttpStatus.UNAUTHORIZED);
val bearerEntryPoint: ServerAuthenticationEntryPoint = BearerTokenServerAuthenticationEntryPoint()
val basicEntryPoint: ServerAuthenticationEntryPoint = HttpStatusServerEntryPoint(HttpStatus.UNAUTHORIZED)

如果您使用自定义AuthenticationEntryPoint对于其中一种或两种机制,请将其一种用于其余步骤。spring-doc.cadn.net.cn

然后,构造并配置一个ServerAuthenticationEntryPointFailureHandler对于每一个:spring-doc.cadn.net.cn

AuthenticationFailureHandler bearerFailureHandler = new ServerAuthenticationEntryPointFailureHandler(bearerEntryPoint);
bearerFailureHandler.setRethrowAuthenticationServiceException(true);
AuthenticationFailureHandler basicFailureHandler = new ServerAuthenticationEntryPointFailureHandler(basicEntryPoint);
basicFailureHandler.setRethrowAuthenticationServiceException(true)
val bearerFailureHandler: AuthenticationFailureHandler = ServerAuthenticationEntryPointFailureHandler(bearerEntryPoint)
bearerFailureHandler.setRethrowAuthenticationServiceException(true)
val basicFailureHandler: AuthenticationFailureHandler = ServerAuthenticationEntryPointFailureHandler(basicEntryPoint)
basicFailureHandler.setRethrowAuthenticationServiceException(true)

最后,将每个身份验证失败处理程序连接到 DSL,如下所示:spring-doc.cadn.net.cn

http
    .httpBasic((basic) -> basic.authenticationFailureHandler(basicFailureHandler))
    .oauth2ResourceServer((oauth2) -> oauth2.authenticationFailureHandler(bearerFailureHandler))
http {
    httpBasic {
        authenticationFailureHandler = basicFailureHandler
    }
    oauth2ResourceServer {
        authenticationFailureHandler = bearerFailureHandler
    }
}

选择退出步骤

选择退出 6.0 默认值并继续通过AuthenticationServiceException上 到ServerAuthenticationEntryPoints,您可以按照与上述相同的步骤进行作,但 setrethrowAuthenticationServiceException设置为 false。spring-doc.cadn.net.cn

@Configuration注解

在 6.0 中,@Configuration@EnableWebFluxSecurity@EnableReactiveMethodSecurity.spring-doc.cadn.net.cn

为了为此做好准备,无论您在哪里使用这些注解之一,您都可能需要将@Configuration. 例如@EnableReactiveMethodSecurity更改自:spring-doc.cadn.net.cn

@EnableReactiveMethodSecurity
public class MyConfiguration {
	// ...
}
@EnableReactiveMethodSecurity
open class MyConfiguration {
	// ...
}
@Configuration
@EnableReactiveMethodSecurity
public class MyConfiguration {
	// ...
}
@Configuration
@EnableReactiveMethodSecurity
open class MyConfiguration {
	// ...
}

解决 OAuth2 客户端弃用问题

ServerOAuth2AuthorizedClientExchangeFilterFunction

方法setAccessTokenExpiresSkew(…​)可以用以下之一代替:spring-doc.cadn.net.cn

方法setClientCredentialsTokenResponseClient(…​)可以用构造函数替换ServerOAuth2AuthorizedClientExchangeFilterFunction(ReactiveOAuth2AuthorizedClientManager).spring-doc.cadn.net.cn

有关详细信息,请参阅客户端凭据spring-doc.cadn.net.cn

WebSessionOAuth2ServerAuthorizationRequestRepository

方法setAllowMultipleAuthorizationRequests(…​)没有直接替代品。spring-doc.cadn.net.cn

UnAuthenticatedServerOAuth2AuthorizedClientRepository

班级UnAuthenticatedServerOAuth2AuthorizedClientRepository没有直接替代品。类的用法可以替换为AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager.spring-doc.cadn.net.cn

@Configuration@Enable*附注

在 6.0 中,所有 Spring Security 的@Enable*注释具有@Configuration删除。 虽然很方便,但它与其他 Spring 项目不一致,尤其是 Spring Framework 的@Enable*附注。 此外,还引入了对@Configuration(proxyBeanMethods=false)在 Spring Framework 中提供了另一个删除@Configurationmeta-comments 来自 Spring Security 的@Enable*注释,并允许用户选择加入他们首选的配置模式。spring-doc.cadn.net.cn

以下注释具有@Configuration删除:spring-doc.cadn.net.cn

例如,如果您使用@EnableWebFluxSecurity,您将需要更改:spring-doc.cadn.net.cn

@EnableWebFluxSecurity
public class SecurityConfig {
	// ...
}
@Configuration
@EnableWebFluxSecurity
public class SecurityConfig {
	// ...
}

这同样适用于上面列出的所有其他注释。spring-doc.cadn.net.cn