Web 迁移
支持相对 URI
当重定向到登录端点时,Spring Security 过去更喜欢绝对 URI。 例如,如果您按如下方式设置登录页面:
-
Java
-
Kotlin
-
Xml
http
// ...
.formLogin((form) -> form.loginPage("/my-login"))
// ...
http {
formLogin {
loginPage = "/my-login"
}
}
<http ...>
<form-login login-page="/my-login"/>
</http>
然后当重定向到/my-login
Spring Security 将使用Location:
如下所示:
302 Found
// ...
Location: https://myapp.example.org/my-login
但是,鉴于 RFC 所基于的 RFC 现已过时,因此不再需要这样做。
在 Spring Security 7 中,这已更改为使用相对 URI,如下所示:
302 Found
// ...
Location: /my-login
大多数应用程序不会注意到差异。
但是,如果此更改导致问题,您可以通过将favorRelativeUrls
价值:
-
Java
-
Kotlin
-
Xml
LoginUrlAuthenticationEntryPoint entryPoint = new LoginUrlAuthenticationEntryPoint("/my-login");
entryPoint.setFavorRelativeUris(false);
http
// ...
.exceptionHandling((exceptions) -> exceptions.authenticaitonEntryPoint(entryPoint))
// ...
LoginUrlAuthenticationEntryPoint entryPoint = LoginUrlAuthenticationEntryPoint("/my-login")
entryPoint.setFavorRelativeUris(false)
http {
exceptionHandling {
authenticationEntryPoint = entryPoint
}
}
<http entry-point-ref="myEntryPoint">
<!-- ... -->
</http>
<b:bean id="myEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<b:property name="favorRelativeUris" value="true"/>
</b:bean>
端口解析器
Spring Security 使用名为PortResolver
为 Internet Explorer 中的 bug 提供解决方法。
该解决方法不再需要,并且在某些情况下可能会导致用户出现问题。
因此,Spring Security 7 将删除PortResolver
接口。
为了准备此更改,用户应公开PortResolver.NO_OP
作为名为portResolver
.
这确保了PortResolver
使用的实现是无作(例如,什么都不做),它模拟删除PortResolver
.
示例配置如下:
-
Java
-
Kotlin
-
Xml
@Bean
PortResolver portResolver() {
return PortResolver.NO_OP;
}
@Bean
open fun portResolver(): PortResolver {
return PortResolver.NO_OP
}
<util:constant id="portResolver"
static-field="org.springframework.security.web.PortResolver.NO_OP">
默认使用 PathPatternRequestMatcher
在 Spring Security 7 中,AntPathRequestMatcher
和MvcRequestMatcher
不再受支持,Java DSL 要求所有 URI 都是绝对的(减去任何上下文根)。
届时,Spring Security 7 将使用PathPatternRequestMatcher
默认情况下。
要检查您对此更改的准备情况,您可以发布此 Bean:
-
Java
-
Kotlin
-
Xml
@Bean
PathPatternRequestMatcherBuilderFactoryBean requestMatcherBuilder() {
return new PathPatternRequestMatcherBuilderFactoryBean();
}
@Bean
fun requestMatcherBuilder(): PathPatternRequestMatcherBuilderFactoryBean {
return PathPatternRequestMatcherBuilderFactoryBean()
}
<b:bean class="org.springframework.security.config.web.PathPatternRequestMatcherBuilderFactoryBean"/>
这将告诉 Spring Security DSL 使用PathPatternRequestMatcher
对于它构造的所有请求匹配器。
如果您直接构造一个对象(而不是让 DSL 构造它),则具有setRequestMatcher
方法。您还应该主动指定一个PathPatternRequestMatcher
那里也有。
迁移exitUserUrl
和switchUserUrl
请求匹配器SwitchUserFilter
SwitchUserFilter
,构造一个AntPathRequestMatcher
在其setExitUserUrl
和setSwitchUserUrl
方法。
这将更改为PathPatternRequestMatcher
在 Spring Security 7 中。
要准备此更改,请调用setExitUserMatcher
和setSwithcUserMatcher
提供此PathPatternRequestMatcher
提前。
也就是说,更改以下内容:
-
Java
-
Kotlin
SwitchUserFilter switchUser = new SwitchUserFilter();
// ... other configuration
switchUser.setExitUserUrl("/exit/impersonate");
val switchUser = SwitchUserFilter()
// ... other configuration
switchUser.setExitUserUrl("/exit/impersonate")
到这个:
-
Java
-
Kotlin
SwitchUserFilter switchUser = new SwitchUserFilter();
// ... other configuration
switchUser.setExitUserMatcher(PathPatternRequestMatcher.withDefaults().matcher(HttpMethod.POST, "/exit/impersonate"));
val switchUser = SwitchUserFilter()
// ... other configuration
switchUser.setExitUserMatcher(PathPatternRequestMatcher.withDefaults().matcher(HttpMethod.POST, "/exit/impersonate"))
迁移filterProcessingUrl
请求匹配器AbstractAuthenticationProcessingFilter
实现
Spring Security 6 转换通过setFilterProcessingUrl
设置为AntPathRequestMatcher
.
在 Spring Security 7 中,这将更改为PathPatternRequestMatcher
.
如果您直接调用setFilterProcessingUrl
在扩展的过滤器上AbstractAuthenticationProcessingFilter
喜欢UsernamePasswordAuthenticationFilter
,OAuth2LoginAuthenticationFilter
,Saml2WebSsoAuthenticationFilter
,OneTimeTokenAuthenticationFilter
或WebAuthnAuthenticationFilter
叫setRequiredAuthenticationRequestMatcher
而是提供PathPatternRequestMatcher
提前。
也就是说,更改以下内容:
-
Java
-
Kotlin
UsernamePasswordAuthenticationFilter usernamePassword = new UsernamePasswordAuthenticationFilter(authenticationManager);
usernamePassword.setFilterProcessingUrl("/my/processing/url");
val usernamePassword = UsernamePasswordAuthenticationFilter(authenticationManager)
usernamePassword.setFilterProcessingUrl("/my/processing/url")
到这个:
-
Java
-
Kotlin
UsernamePasswordAuthenticationFilter usernamePassword = new UsernamePasswordAuthenticationFilter(authenticationManager);
RequestMatcher requestMatcher = PathPatternRequestMatcher.withDefaults().matcher("/my/processing/url");
usernamePassword.setRequest(requestMatcher);
val usernamePassword = UsernamePasswordAuthenticationFilter(authenticationManager)
val requestMatcher = PathPatternRequestMatcher.withDefaults().matcher("/my/processing/url")
usernamePassword.setRequest(requestMatcher)
Most applications use the DSL instead of setting the `filterProcessingUrl` directly on a filter instance.
迁移 CAS 代理接收器请求匹配器
Spring Security 6 将任何配置的proxyReceptorUrl
到与请求结尾匹配的请求匹配器,即/**/proxy/receptor
.
在 Spring Security 7 中,不允许此模式,并将更改为PathPatternRequestMatcher
.
同样在 Spring Security 7m 中,URL 应该是绝对的,排除任何上下文路径,如下所示:/proxy/receptor
.
因此,为了准备这些变化,您可以使用setProxyReceptorRequestMatcher
而不是setProxyReceptorUrl
.
也就是说,更改以下内容:
-
Java
-
Kotlin
casAuthentication.setProxyReceptorUrl("/proxy/receptor");
casAuthentication.setProxyReceptorUrl("/proxy/receptor")
到这个:
-
Java
-
Kotlin
casAuthentication.setProxyReceptorUrl(PathPatternRequestMatcher.withDefaults().matcher("/proxy/receptor"));
casAuthentication.setProxyReceptorUrl(PathPatternRequestMatcher.withDefaults().matcher("/proxy/receptor"))
迁移 WebInvocationPrivilegeEvaluator
如果您使用的是 Spring Security 的 JSP Taglibs 或正在使用WebInvocationPrivilegeEvaluator
直接注意以下更改:
-
RequestMatcherWebInvocationPrivilegeEvaluator
被弃用,取而代之的是AuthorizationManagerWebInvocationPrivilegeEvaluator
-
HandlerMappingIntrospectorRequestTransformer
被弃用,取而代之的是PathPatternRequestTransformer
如果您不直接构建这些更改,您可以通过发布PathPatternRequestTransformer
这样:
-
Java
-
Kotlin
-
Xml
@Bean
HttpServletRequestTransformer pathPatternRequestTransformer() {
return new PathPatternRequestTransformer();
}
@Bean
fun pathPatternRequestTransformer(): HttpServletRequestTransformer {
return PathPatternRequestTransformer()
}
<b:bean class="org.springframework.security.web.access.PathPatternRequestTransformer"/>
Spring Security 将以此为使用新实现的信号。
One difference you may notice is that `AuthorizationManagerWebPrivilegeInvocationEvaluator` allows the authentication to be `null` if the authorization rule is `permitAll`. Test your endpoints that `permitAll` in case JSP requests using this same require should not, in fact, be permitted.
在授权规则中包括 Servlet 路径前缀
对于许多应用程序来说,上述内容不会有任何区别,因为最常见的是,列出的所有 URI 都与默认 servlet 匹配。
但是,如果您有其他具有 servlet 路径前缀的 servlet,那么现在需要单独提供这些路径。
例如,如果我有一个 Spring MVC 控制器,其中@RequestMapping("/orders")
并且我的 MVC 应用程序被部署到/mvc
(而不是默认的 servlet),则此端点的 URI 为/mvc/orders
.
从历史上看,Java DSL 没有一种简单的方法来指定 servlet 路径前缀,Spring Security 试图推断它。
随着时间的推移,我们了解到这些推理会让开发人员感到惊讶。 现在,无需将此责任从开发人员身上移开,而是更简单地指定 servlet 路径前缀,如下所示:
PathPatternRequestParser.Builder servlet = PathPatternRequestParser.withDefaults().basePath("/mvc"); http .authorizeHttpRequests((authorize) -> authorize .requestMatchers(servlet.pattern("/orders/**").matcher()).authenticated() )
对于属于默认 servlet 的路径,请使用PathPatternRequestParser.withDefaults()
相反:
PathPatternRequestParser.Builder request = PathPatternRequestParser.withDefaults(); http .authorizeHttpRequests((authorize) -> authorize .requestMatchers(request.pattern("/js/**").matcher()).authenticated() )
请注意,这并不适用于所有类型的 servlet,因为并非所有 servlet 都有路径前缀。
例如,与 JSP Servlet 匹配的表达式可能使用 ant 模式/*/.jsp
.
目前还没有通用的替代品,因此建议您使用RegexRequestMatcher
这样:regexMatcher("\\.jsp$")
.
对于许多应用程序来说,这不会有什么区别,因为最常见的是,列出的所有 URI 都与默认 servlet 匹配。
使用 RedirectToHttps 而不是通道安全性
几年前,HTTPS 总体上是一个性能和配置问题,应用程序希望能够决定应用程序的哪些部分需要 HTTPS。
requires-channel
在 XML 中,并且requiresChannel
在 Java Config 中,允许在配置应用程序时考虑到这一点:
-
Java
-
Kotlin
-
Xml
http
.requiresChannel((channel) -> channel
.requestMatchers("/secure/**").requiresSecureChannel()
.requestMatchers("/insecure/**").requiresInsecureChannel()
)
http {
requiresChannel {
secure("/secure/**")
seccure("/insecure/**", "REQUIRES_INSECURE_CHANNEL")
}
}
<http>
<intercept-url pattern="/secure/**" access="authenticated" requires-channel="REQUIRES_SECURE_CHANNEL"/>
<intercept-url pattern="/insecure/**" access="authenticated" requires-channel="REQUIRES_INSECURE_CHANNEL"/>
</http>
新式应用程序应始终需要 HTTPS。 但是,有时,例如在本地开发时,人们希望应用程序使用 HTTP。 或者,您可能有持续的情况需要应用程序的一部分是 HTTP。
在任何情况下,您都可以迁移到redirect-to-https-request-matcher-ref
和redirectToHttps
通过首先构造一个RequestMatcher
其中包含需要重定向到 HTTPS 的所有情况。
然后,您可以像这样引用该请求匹配器:
-
Java
-
Kotlin
-
Xml
http
.redirectToHttps((https) -> https.requestMatchers("/secure/**"))
// ...
var secure: RequestMatcher = PathPatternRequestMatcher.withDefaults().pattern("/secure/**")
http {
redirectToHttps {
requestMatchers = secure
}
// ...
}
<b:bean id="builder" class="org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher$Builder"/>
<b:bean id="secure" class="org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher" factory-bean="builder" factory-method="matcher">
<b:constructor-arg value="/secure/**"/>
</b:bean>
<http redirect-to-https-request-matcher-ref="secure">
<intercept-url pattern="/secure/**" access="authenticated"/>
<intercept-url pattern="/insecure/**" access="authenticated"/>
<!-- ... -->
</http>
如果您有几种需要 HTTP 的情况,请考虑使用 |
用setCookieCustomizer
而不是单独的二传手
支持更简单的 API,CookieCsrfTokenRepository#setCookieCustomizer
允许您更改 cookie 的任何方面,将setCookieHttpOnly
,setCookieMaxAge
,setSecure
和setCookieDomain
.
更改此内容:
-
Java
-
Kotlin
CookeCsrfTokenRepository csrf = CookeCsrfTokenRepository.withHttpOnlyFalse();
csrf.setCookieMaxAge(86400)
val csrf = CookeCsrfTokenRepository.withHttpOnlyFalse()
csrf.setCookieMaxAge(86400)
到这个:
-
Java
-
Kotlin
CookeCsrfTokenRepository csrf = CookeCsrfTokenRepository.withHttpOnlyFalse();
csrf.setCookieCustomizer((c) -> c.maxAge(86400));
val csrf = CookeCsrfTokenRepository.withHttpOnlyFalse()
csrf.setCookieCustomizer { -> it.maxAge(86400) }