servlet-authorization-authorize-http-requests.md 8.4 KB
Newer Older
dallascao's avatar
dallascao 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
# 授权 HttpServletRequestwithAuthorizationFilter

本节通过深入研究[授权](index.html#servlet-authorization)在基于 Servlet 的应用程序中的工作方式,构建了[Servlet Architecture and Implementation](../architecture.html#servlet-architecture)

|   |`AuthorizationFilter`取代[`FilterSecurityInterceptor`](authorize-requests.html# Servlet-authorization-filtersecurityinterceptor)。<br/>要保持向后兼容,`FilterSecurityInterceptor`仍然是默认值。<br/>本节讨论`AuthorizationFilter`如何工作以及如何覆盖默认配置。|
|---|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

[`AuthorizationFilter`](https://DOCS. Spring.io/ Spring-security/site/DOCS/5.6.2/api/org/springframework/security/web/access/intercept/intercept/authorizationfilter.html)为`HttpServletRequest`s 提供[授权](index.html#servlet-authorization)。它作为[安全过滤器](../architecture.html#servlet-security-filters)中的一个插入到[FilterchainProxy](../architecture.html#servlet-filterchainproxy)中。

声明`SecurityFilterChain`时,可以重写默认值。不要使用[`authorizeRequests`](# Servlet-authorize-requests-defaults),而是使用`authorizeHttpRequests`,就像这样:

例 1。使用 AuthorizeHttpRequests

爪哇

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

    return http.build();
}
```

这在以下几个方面改进了`authorizeRequests`:

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

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

3. Bean-基于配置支持。

当使用`authorizeHttpRequests`而不是`authorizeRequests`时,则使用[`AuthorizationFilter`](https://DOCS. Spring.io/ Spring-security/site/DOCS/5.6.2/api/org/springframework/security/web/access/intercept/Authorizationfilter.html)代替[<<<requests.html>](authority-requests.html# Servlet-authority-filtersecurityptor)。

茶陵後's avatar
茶陵後 已提交
39
![授权过滤器](https://docs.spring.io/spring-security/reference/_images/servlet/authorization/authorizationfilter.png)
dallascao's avatar
dallascao 已提交
40 41 42

图 1。授权 HttpServletRequest

茶陵後's avatar
茶陵後 已提交
43
* ![number 1](https://docs.spring.io/spring-security/reference/_images/icons/number_1.png)首先,`AuthorizationFilter`[SecurityContextholder](../authentication/architecture.html#servlet-authentication-securitycontextholder)得到[认证](../authentication/architecture.html#servlet-authentication-authentication)。它将此包在`Supplier`中,以延迟查找。
dallascao's avatar
dallascao 已提交
44

茶陵後's avatar
茶陵後 已提交
45
* ![number 2](https://docs.spring.io/spring-security/reference/_images/icons/number_2.png)秒,`AuthorizationFilter``HttpServletRequest``FilterInvocation`、<DOCS. Spring.io/ Spring-security/site/DOCS/5.6.2/api/org/springframework/security/web/filterinvocation.html)中创建一个[`HttpServletRequest`、`HttpServletResponse`和`FilterChain`。
dallascao's avatar
dallascao 已提交
46

茶陵後's avatar
茶陵後 已提交
47
* ![number 3](https://docs.spring.io/spring-security/reference/_images/icons/number_3.png)接下来,它将`Supplier<Authentication>``FilterInvocation`传递给[`AuthorizationManager`]。
dallascao's avatar
dallascao 已提交
48

茶陵後's avatar
茶陵後 已提交
49
  * ![number 4](https://docs.spring.io/spring-security/reference/_images/icons/number_4.png)如果拒绝授权,将抛出`AccessDeniedException`。在这种情况下,[`ExceptionTranslationFilter`](../architecture.html# Servlet-ExceptionTranslationFilter)处理`AccessDeniedException`
dallascao's avatar
dallascao 已提交
50

茶陵後's avatar
茶陵後 已提交
51
  * ![number 5](https://docs.spring.io/spring-security/reference/_images/icons/number_5.png)如果访问被授予,`AuthorizationFilter`继续使用[滤清链](../architecture.html#servlet-filters-review),这允许应用程序正常处理。
dallascao's avatar
dallascao 已提交
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162

通过按优先级顺序添加更多规则,我们可以将安全性配置为具有不同的规则。

例 2。授权请求

爪哇

```
@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("hasRole('ADMIN') and hasRole('DBA')")   (4)
			.anyRequest().denyAll()                                                (5)
		);

	return http.build();
}
```

|**1**|指定了多个授权规则。<br/>每个规则都按照它们被声明的顺序被考虑。|
|-----|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|**2**|我们指定了任何用户都可以访问的多个 URL 模式。<br/>具体来说,如果 URL 以“/resources/”开头,等于“/signup”或等于“/about”,则任何用户都可以访问请求。|
|**3**|任何以“/admin/”开头的 URL 都将被限制为具有角色“role\_admin”的用户。<br/>你将注意到,由于我们正在调用`hasRole`方法,因此我们不需要指定“role\_”前缀。|
|**4**|任何以“/db/”开头的 URL 都要求用户同时具有“role\_admin”和“role\_DBA”。<br/>你将注意到,由于我们使用的是`hasRole`表达式,因此我们不需要指定“role\_”前缀。|
|**5**|任何尚未匹配的 URL 都将被拒绝访问。<br/>如果你不想意外地忘记更新授权规则,这是一个很好的策略。|

你可以通过构建自己的[`RequestMatcherDelegatingAuthorizationManager`](architecture.html#authz-delegate-authorization-manager)来采用基于 Bean 的方法,如下所示:

例 3。配置 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());
}
```

你还可以为任何请求匹配器连接[你自己的自定义授权管理器](architecture.html#authz-custom-authorization-manager)

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

例 4。自定义授权管理器

爪哇

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

    return http.build();
}
```

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

例 5。所有请求的自定义授权管理器

爪哇

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

    return http.build();
}
```

[授权体系结构](architecture.html)[使用 FilterSecurityInterceptor 授权 HTTP 请求](authorize-requests.html)