|
此版本仍在开发中,尚未被视为稳定版本。如需最新稳定版本,请使用 Spring Security 7.0.4! |
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所基于的内容现在已经过时,因此这现在已经不再必要。
在 Spring Security 7 中,这被更改为了使用相对 URI,如下所示:
302 Found
// ...
Location: /my-login
大多数应用程序不会注意到任何差异。
然而,如果此更改导致问题,您可以将favorRelativeUrls值切换回Spring Security 6的行为:
-
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的 API 来提供一个针对 Internet Explorer 中的一个错误的 workaround。
这个 workaround 已经不再必要,并且在某些场景下可能会给用户带来问题。因此,Spring Security 7 将移除 PortResolver 接口。
要为此变更做准备,用户应该将PortResolver.NO_OP暴露为一个名为portResolver的Bean。
这确保了使用的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。
在XML中,您可以使用request-matcher="path"代替request-matcher="ant"或request-matcher="mvc",如下所示:
-
Xml
<http auto-config="true">
<intercept-url pattern="/my/login/**" access="authenticated" request-matcher="path"/>
</http>
迁移exitUserUrl和switchUserUrl请求匹配器在SwitchUserFilter
SwitchUserFilter, 在其AntPathRequestMatcher和setExitUserUrl方法中构造一个setSwitchUserUrl。
这将在Spring Security 7中改为使用PathPatternRequestMatcher。
要为这一变更做准备,请调用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"))
迁移filterProcessingUrlSpring 框架中的请求匹配器AbstractAuthenticationProcessingFilter实现
Spring Security 6 将通过 setFilterProcessingUrl 配置的任何处理端点转换为 AntPathRequestMatcher。
在 Spring Security 7 中,这将变为 PathPatternRequestMatcher。
如果您直接在扩展AbstractAuthenticationProcessingFilter的过滤器(例如UsernamePasswordAuthenticationFilter、OAuth2LoginAuthenticationFilter、Saml2WebSsoAuthenticationFilter、OneTimeTokenAuthenticationFilter或WebAuthnAuthenticationFilter)上调用setFilterProcessingUrl,请改为调用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 7 中,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标签库,或直接使用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,则这些路径现在需要单独提供。则这些路径现在需要单独提供。
例如,如果我有一个使用@RequestMapping("/orders")的Spring MVC控制器,并且我的MVC应用程序部署到了/mvc(而不是默认的服务路径),那么此端点的URI为/mvc/orders。
历史上,Java DSL 没有简单的方法来指定Servlet路径前缀,Spring Security 曾尝试推断它。
随着时间的推移,我们了解到这些推断会让开发者感到惊讶。 现在,与其将这个责任从开发者那里拿走,不如这样指定servlet路径前缀要简单得多:
PathPatternRequestMatcher.Builder servlet = PathPatternRequestMatcher.withDefaults().basePath("/mvc");
http
.authorizeHttpRequests((authorize) -> authorize
.requestMatchers(servlet.matcher("/orders/**")).authenticated()
)
对于属于默认Servlet的路径,请使用PathPatternRequestMatcher.withDefaults()代替:
PathPatternRequestMatcher.Builder request = PathPatternRequestMatcher.withDefaults();
http
.authorizeHttpRequests((authorize) -> authorize
.requestMatchers(request.matcher("/js/**")).authenticated()
)
注意,这并不涵盖所有类型的servlet,因为并非所有的servlet都有路径前缀。
例如,匹配JSP Servlet的表达式可能会使用ant模式 /*/.jsp。
还没有通用的替代品,因此建议您使用RegexRequestMatcher,例如:regexMatcher("\\.jsp$")。
对于大多数应用程序来说这不会有任何区别,因为通常所有列出的URI都会被默认Servlet匹配。
使用 RedirectToHttps 替代通道安全
几年前,HTTPS 大多时候是一个性能和配置方面的问题,因此应用程序需要能够决定哪些应用段落需要使用 HTTPS。
requires-channel 在 XML 配置中和 requiresChannel 在 Java 配置中用于根据需要配置应用程序:
-
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。
在任何情况下,您可以通过首先构建一个包含所有需要重定向到HTTPS的情况的redirect-to-https-request-matcher-ref来迁移至redirectToHttps和RequestMatcher。
然后您可以像这样引用该请求匹配器:
-
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而不是单独的 setter 方法
在更简单易用的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) }