SpringSecurity系列——授权Http请求day4-2(源于官网5.7.2版本)

SpringSecurity系列——授权Http请求day4-2(源于官网5.7.2版本)

  • 前言
  • Authorize HttpServletRequests with AuthorizationFilter(使用 AuthorizationFilter 授权 HttpServletRequests)
  • 解释概括

前言

源于官方最新5.7.2文档,若你觉得官方文档阅读起来很枯燥,内容复杂,我提供了解析概括在每个部分的结尾,我对官方文档的内容做了一些改变,实例代码我会在后续进行更新,请查看如:SpringSecurity系列——认证架构实例代码的文章

但是如果你有能力,还是推荐直接阅读官方文档

Authorize HttpServletRequests with AuthorizationFilter(使用 AuthorizationFilter 授权 HttpServletRequests)

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

AuthorizationFilter 为 HttpServletRequests 提供授权。 它作为安全过滤器之一插入到 FilterChainProxy 中。

您可以在声明 SecurityFilterChain 时覆盖默认值。 不要使用 authorizeRequests,而是使用 authorizeHttpRequests,如下所示:

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

    return http.build();
}

这以多种方式改进了 authorizeRequests:

  1. 使用简化的 AuthorizationManager API,而不是元数据源、配置属性、决策管理器和选民。 这简化了重用和定制。
  2. 延迟身份验证查找。 而不是需要为每个请求查找身份验证,它只会在授权决策需要身份验证的请求中查找它。
  3. 基于 Bean 的配置支持。

当使用 authorizeHttpRequests 代替 authorizeRequests 时,则使用 AuthorizationFilter 代替 FilterSecurityInterceptor。
SpringSecurity系列——授权Http请求day4-2(源于官网5.7.2版本)_第1张图片

  1. 首先,AuthorizationFilter 从 SecurityContextHolder 获得一个 Authentication。 它将其包装在供应商中以延迟查找。
  2. 其次,AuthorizationFilter 从 HttpServletRequest、HttpServletResponse 和 FilterChain 创建一个 FilterInvocation。
  3. 接下来,它将 Supplier 和 FilterInvocation 传递给 AuthorizationManager。
    4. 如果授权被拒绝,则抛出 AccessDeniedException。 在这种情况下,ExceptionTranslationFilter 处理 AccessDeniedException。
    5. 如果授予访问权限,AuthorizationFilter 继续使用允许应用程序正常处理的 FilterChain。

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

//授权请求
@Bean
SecurityFilterChain web(HttpSecurity http) throws Exception {
	http
		// ...
		//指定了多个授权规则。  每个规则都按照它们被声明的顺序来考虑。
		.authorizeHttpRequests(authorize -> authorize
		// 我们指定了任何用户都可以访问的多个 URL 模式。  具体来说,如果 URL 以“/resources/”开头、等于“/signup”或等于“/about”,则任何用户都可以访问请求。
			.mvcMatchers("/resources/**", "/signup", "/about").permitAll()
			//任何以“/admin/”开头的 URL 都将被限制为具有“ROLE_ADMIN”角色的用户。  您会注意到,由于我们正在调用 hasRole 方法,因此我们不需要指定“ROLE_”前缀。
			.mvcMatchers("/admin/**").hasRole("ADMIN")
			// 任何以“/db/”开头的 URL 都要求用户同时拥有“ROLE_ADMIN”和“ROLE_DBA”。  您会注意到,由于我们使用了 hasRole 表达式,我们不需要指定“ROLE_”前缀。
			.mvcMatchers("/db/**").access((authentication, request) ->
			    Optional.of(hasRole("ADMIN").check(authentication, request))
			        .filter((decision) -> !decision.isGranted())
			        .orElseGet(() -> hasRole("DBA").check(authentication, request));
			)
			// 任何尚未匹配的 URL 都将被拒绝访问。  如果您不想意外忘记更新授权规则,这是一个很好的策略。
			.anyRequest().denyAll()
		);

	return http.build();
}

您可以通过构建自己的 RequestMatcherDelegatingAuthorizationManager 来采用基于 bean 的方法,如下所示:

@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());
}

您还可以为任何请求匹配器连接您自己的自定义授权管理器。

以下是将自定义授权管理器映射到 my/authorized/endpoint 的示例:

@Bean
SecurityFilterChain web(HttpSecurity http) throws Exception {
    http
        .authorizeHttpRequests((authorize) -> authorize
            .mvcMatchers("/my/authorized/endpoint").access(new CustomAuthorizationManager());
        )
        // ...

    return http.build();
}

或者您可以为所有请求提供它,如下所示:

@Bean
SecurityFilterChain web(HttpSecurity http) throws Exception {
    http
        .authorizeHttpRequests((authorize) -> authorize
            .anyRequest.access(new CustomAuthorizationManager());
        )
        // ...

    return http.build();
}

默认情况下,AuthorizationFilter 不适用于 DispatcherType.ERROR 和 DispatcherType.ASYNC。 我们可以使用 shouldFilterAllDispatcherTypes 方法配置 Spring Security 以将授权规则应用于所有调度程序类型:

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

    return http.build();
}

解释概括

  1. AuthorizationFilter取代 FilterSecurityInterceptor
  2. AuthorizationFilter 为 HttpServletRequests 提供授权
  3. 我们需要在使用SecurityFilterChain 时覆盖默认值。 使用 authorizeHttpRequests
  4. 我们可以自定义多种策略对授权自定义

你可能感兴趣的:(笔记,Java学习,#,SpringSecurity,http,java,servlet)