SpringSecurity系列——授权Http请求day4-2(源于官网5.7.2版本)
前言
源于官方最新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:
- 使用简化的 AuthorizationManager API,而不是元数据源、配置属性、决策管理器和选民。 这简化了重用和定制。
- 延迟身份验证查找。 而不是需要为每个请求查找身份验证,它只会在授权决策需要身份验证的请求中查找它。
- 基于 Bean 的配置支持。
当使用 authorizeHttpRequests 代替 authorizeRequests 时,则使用 AuthorizationFilter 代替 FilterSecurityInterceptor。
- 首先,AuthorizationFilter 从 SecurityContextHolder 获得一个 Authentication。 它将其包装在供应商中以延迟查找。
- 其次,AuthorizationFilter 从 HttpServletRequest、HttpServletResponse 和 FilterChain 创建一个 FilterInvocation。
- 接下来,它将
Supplier<Authentication>
和 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();
}
解释概括
- AuthorizationFilter取代 FilterSecurityInterceptor
- AuthorizationFilter 为 HttpServletRequests 提供授权
- 我们需要在使用SecurityFilterChain 时覆盖默认值。 使用 authorizeHttpRequests
- 我们可以自定义多种策略对授权自定义