对于最新的稳定版本,请使用 Spring Security 6.3.1

对于最新的稳定版本,请使用 Spring Security 6.3.1

FilterSecurityInterceptor正在被 AuthorizationFilter 替换。 请考虑改用它。

本节以 Servlet 架构和实现为基础,深入探讨授权在基于 Servlet 的应用程序中的工作原理。

FilterSecurityInterceptor 为 s. 它作为安全过滤器之一插入到 FilterChainProxy 中。HttpServletRequest

FilterSecurityInterceptor
图 1.授权 HttpServletRequest
  • 数字 1首先,从 SecurityContextHolder 获取身份验证FilterSecurityInterceptor

  • 数字 2其次,从 、 和 创建一个 FilterInvocation,这些调用被传递到 .FilterSecurityInterceptorHttpServletRequestHttpServletResponseFilterChainFilterSecurityInterceptor

  • 数字 3接下来,它传递 to 以获取 s。FilterInvocationSecurityMetadataSourceConfigAttribute

  • 数字 4最后,它将 、 和 s 传递给 xref:servlet/authorization.adoc#authz-access-decision-manager'AccessDecisionManager'。AuthenticationFilterInvocationConfigAttribute

    • 数字 5如果授权被拒绝,则抛出 an。 在本例中,ExceptionTranslationFilter 处理 .AccessDeniedExceptionAccessDeniedException

    • 数字 6如果授予访问权限,则继续使用 FilterChain,允许应用程序正常处理。FilterSecurityInterceptor

默认情况下,Spring Security 的授权将要求对所有请求进行身份验证。 显式配置如下所示:

每个请求都必须经过身份验证
  • Java

  • XML

  • Kotlin

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
	http
		// ...
		.authorizeRequests(authorize -> authorize
			.anyRequest().authenticated()
		);
	return http.build();
}
<http>
	<!-- ... -->
	<intercept-url pattern="/**" access="authenticated"/>
</http>
@Bean
open fun filterChain(http: HttpSecurity): SecurityFilterChain {
    http {
        // ...
        authorizeRequests {
            authorize(anyRequest, authenticated)
        }
    }
    return http.build()
}

我们可以通过按优先级顺序添加更多规则来配置 Spring Security 以具有不同的规则。

授权请求
  • Java

  • XML

  • Kotlin

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
	http
		// ...
		.authorizeRequests(authorize -> authorize                                  (1)
			.mvcMatchers("/resources/**", "/signup", "/about").permitAll()         (2)
			.mvcMatchers("/admin/**").hasRole("ADMIN")                             (3)
			.mvcMatchers("/db/**").access("hasRole('ADMIN') and hasRole('DBA')")   (4)
			.anyRequest().denyAll()                                                (5)
		);
	return http.build();
}
<http> (1)
	<!-- ... -->
	(2)
	<intercept-url pattern="/resources/**" access="permitAll"/>
	<intercept-url pattern="/signup" access="permitAll"/>
	<intercept-url pattern="/about" access="permitAll"/>

	<intercept-url pattern="/admin/**" access="hasRole('ADMIN')"/> (3)
	<intercept-url pattern="/db/**" access="hasRole('ADMIN') and hasRole('DBA')"/> (4)
	<intercept-url pattern="/**" access="denyAll"/> (5)
</http>
@Bean
open fun filterChain(http: HttpSecurity): SecurityFilterChain {
   http {
        authorizeRequests { (1)
            authorize("/resources/**", permitAll) (2)
            authorize("/signup", permitAll)
            authorize("/about", permitAll)

            authorize("/admin/**", hasRole("ADMIN")) (3)
            authorize("/db/**", "hasRole('ADMIN') and hasRole('DBA')") (4)
            authorize(anyRequest, denyAll) (5)
        }
    }
    return http.build()
}
1 指定了多个授权规则。 每条规则都按其声明的顺序进行考虑。
2 我们指定了任何用户都可以访问的多个 URL 模式。 具体而言,如果 URL 以“/resources/”开头、等于“/signup”或等于“/about”,则任何用户都可以访问请求。
3 任何以“/admin/”开头的 URL 都将仅限于角色为“ROLE_ADMIN”的用户。 您会注意到,由于我们正在调用该方法,因此我们不需要指定“ROLE_”前缀。hasRole
4 任何以“/db/”开头的 URL 都要求用户同时具有“ROLE_ADMIN”和“ROLE_DBA”。 您会注意到,由于我们使用的是表达式,因此我们不需要指定“ROLE_”前缀。hasRole
5 任何尚未匹配的 URL 都将被拒绝访问。 如果您不想意外忘记更新授权规则,这是一个很好的策略。
FilterSecurityInterceptor正在被 AuthorizationFilter 替换。 请考虑改用它。
1 指定了多个授权规则。 每条规则都按其声明的顺序进行考虑。
2 我们指定了任何用户都可以访问的多个 URL 模式。 具体而言,如果 URL 以“/resources/”开头、等于“/signup”或等于“/about”,则任何用户都可以访问请求。
3 任何以“/admin/”开头的 URL 都将仅限于角色为“ROLE_ADMIN”的用户。 您会注意到,由于我们正在调用该方法,因此我们不需要指定“ROLE_”前缀。hasRole
4 任何以“/db/”开头的 URL 都要求用户同时具有“ROLE_ADMIN”和“ROLE_DBA”。 您会注意到,由于我们使用的是表达式,因此我们不需要指定“ROLE_”前缀。hasRole
5 任何尚未匹配的 URL 都将被拒绝访问。 如果您不想意外忘记更新授权规则,这是一个很好的策略。

将 FilterSecurityInterceptor 应用于每个请求

默认情况下,仅对请求应用一次。 这意味着,如果从已过滤的请求调度请求,则将退避并且不执行任何授权检查。 在某些情况下,您可能希望将筛选器应用于每个请求。 您可以使用以下方法将 Spring Security 配置为将授权规则应用于每个请求:FilterSecurityInterceptorFilterSecurityInterceptorfilterSecurityInterceptorOncePerRequest

将 filterSecurityInterceptorOncePerRequest 设置为 false
  • Java

  • XML

@Bean
SecurityFilterChain web(HttpSecurity http) throws Exception {
    http
        .authorizeRequests((authorize) -> authorize
            .filterSecurityInterceptorOncePerRequest(false)
            .anyRequest.authenticated()
        )
        // ...

    return http.build();
}
<http once-per-request="false">
    <intercept-url pattern="/**" access="authenticated"/>
</http>

您还可以根据请求分派器类型配置授权:

允许 ASYNC 调度程序类型
  • Java

  • XML

@Bean
SecurityFilterChain web(HttpSecurity http) throws Exception {
    http
        .authorizeRequests((authorize) -> authorize
            .filterSecurityInterceptorOncePerRequest(false)
            .dispatcherTypeMatchers(DispatcherType.ASYNC).permitAll()
            .anyRequest.authenticated()
        )
        // ...

    return http.build();
}
<http auto-config="true" once-per-request="false">
    <intercept-url request-matcher-ref="dispatcherTypeMatcher" access="permitAll" />
    <intercept-url pattern="/**" access="authenticated"/>
</http>

<b:bean id="dispatcherTypeMatcher" class="org.springframework.security.web.util.matcher.DispatcherTypeRequestMatcher">
    <b:constructor-arg value="ASYNC"/>
</b:bean>