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

使用 AuthorizationFilter 授权 HttpServletRequests

本节以 Servlet 体系结构和实现为基础,深入探讨了授权在基于 Servlet 的应用程序中的工作原理。spring-doc.cn

AuthorizationFilter取代 FilterSecurityInterceptor。 为了保持向后兼容,请保留默认值。 本节讨论工作原理以及如何覆盖默认配置。FilterSecurityInterceptorAuthorizationFilter

AuthorizationFilter 为 s. 它作为 Security Filters 之一插入到 FilterChainProxy 中。HttpServletRequestspring-doc.cn

您可以在声明 . 不要使用 authorizeRequests,而是使用 ,如下所示:SecurityFilterChainauthorizeHttpRequestsspring-doc.cn

使用 authorizeHttpRequests
@Bean
SecurityFilterChain web(HttpSecurity http) throws AuthenticationException {
    http
        .authorizeHttpRequests((authorize) -> authorize
            .anyRequest().authenticated();
        )
        // ...

    return http.build();
}

这在许多方面都有所改进:authorizeRequestsspring-doc.cn

  1. 使用简化的 API,而不是元数据源、配置属性、决策管理器和投票者。 这简化了重用和定制。AuthorizationManagerspring-doc.cn

  2. 延迟查找。 它不需要为每个请求查找身份验证,而只会在授权决策需要身份验证的请求中查找身份验证。Authenticationspring-doc.cn

  3. 基于 Bean 的配置支持。spring-doc.cn

When 使用 而不是 ,则使用 AuthorizationFilter 而不是 FilterSecurityInterceptorauthorizeHttpRequestsauthorizeRequestsspring-doc.cn

authorization过滤器
图 1.授权 HttpServletRequest

我们可以通过按优先顺序添加更多规则来将 Spring Security 配置为具有不同的规则。spring-doc.cn

授权请求
@Bean
SecurityFilterChain web(HttpSecurity http) throws Exception {
	http
		// ...
		.authorizeHttpRequests(authorize -> authorize                                  (1)
			.mvcMatchers("/resources/**", "/signup", "/about").permitAll()         (2)
			.mvcMatchers("/admin/**").hasRole("ADMIN")                             (3)
			.mvcMatchers("/db/**").access((authentication, request) ->
			    Optional.of(hasRole("ADMIN").check(authentication, request))
			        .filter((decision) -> !decision.isGranted())
			        .orElseGet(() -> hasRole("DBA").check(authentication, request));
			)   (4)
			.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 都将被拒绝访问。 如果您不想意外忘记更新授权规则,这是一个很好的策略。

你可以通过构建自己的RequestMatcherDelegatingAuthorizationManager来采用基于 bean 的方法,如下所示:spring-doc.cn

配置 RequestMatcherDelegatingAuthorizationManager
@Bean
SecurityFilterChain web(HttpSecurity http, AuthorizationManager<RequestAuthorizationContext> access)
        throws AuthenticationException {
    http
        .authorizeHttpRequests((authorize) -> authorize
            .anyRequest().access(access)
        )
        // ...

    return http.build();
}

@Bean
AuthorizationManager<RequestAuthorizationContext> requestMatcherAuthorizationManager(HandlerMappingIntrospector introspector) {
    RequestMatcher permitAll =
            new AndRequestMatcher(
                    new MvcRequestMatcher(introspector, "/resources/**"),
                    new MvcRequestMatcher(introspector, "/signup"),
                    new MvcRequestMatcher(introspector, "/about"));
    RequestMatcher admin = new MvcRequestMatcher(introspector, "/admin/**");
    RequestMatcher db = new MvcRequestMatcher(introspector, "/db/**");
    RequestMatcher any = AnyRequestMatcher.INSTANCE;
    AuthorizationManager<HttpRequestServlet> manager = RequestMatcherDelegatingAuthorizationManager.builder()
            .add(permitAll, (context) -> new AuthorizationDecision(true))
            .add(admin, AuthorityAuthorizationManager.hasRole("ADMIN"))
            .add(db, AuthorityAuthorizationManager.hasRole("DBA"))
            .add(any, new AuthenticatedAuthorizationManager())
            .build();
    return (context) -> manager.check(context.getRequest());
}

您还可以为任何请求匹配器连接自己的自定义授权管理器spring-doc.cn

以下是将自定义授权管理器映射到 的示例:my/authorized/endpointspring-doc.cn

自定义授权管理器
@Bean
SecurityFilterChain web(HttpSecurity http) throws Exception {
    http
        .authorizeHttpRequests((authorize) -> authorize
            .mvcMatchers("/my/authorized/endpoint").access(new CustomAuthorizationManager());
        )
        // ...

    return http.build();
}

或者你可以为所有请求提供它,如下所示:spring-doc.cn

所有请求的自定义授权管理器
@Bean
SecurityFilterChain web(HttpSecurity http) throws Exception {
    http
        .authorizeHttpRequests((authorize) -> authorize
            .anyRequest.access(new CustomAuthorizationManager());
        )
        // ...

    return http.build();
}

默认情况下,这不适用于 和 。 我们可以使用以下方法将 Spring Security 配置为将授权规则应用于所有调度程序类型:AuthorizationFilterDispatcherType.ERRORDispatcherType.ASYNCshouldFilterAllDispatcherTypesspring-doc.cn

将 shouldFilterAllDispatcherTypes 设置为 true
@Bean
SecurityFilterChain web(HttpSecurity http) throws Exception {
    http
        .authorizeHttpRequests((authorize) -> authorize
            .shouldFilterAllDispatcherTypes(true)
            .anyRequest.authenticated()
        )
        // ...

    return http.build();
}
@Bean
open fun web(http: HttpSecurity): SecurityFilterChain {
    http {
        authorizeHttpRequests {
            shouldFilterAllDispatcherTypes = true
            authorize(anyRequest, authenticated)
        }
    }
    return http.build()
}