最新の安定バージョンについては、Spring Security 6.4.4 を使用してください! |
AuthorizationFilter で HttpServletRequests を認証する
このセクションは、サーブレットベースのアプリケーション内で認可がどのように機能するかを深く掘り下げて、サーブレットのアーキテクチャと実装に基づいています。
AuthorizationFilter は FilterSecurityInterceptor に取って代わります。下位互換性を維持するために、FilterSecurityInterceptor はデフォルトのままです。このセクションでは、AuthorizationFilter がどのように機能するか、およびデフォルト構成をオーバーライドする方法について説明します。 |
AuthorizationFilter
(Javadoc) は、HttpServletRequest
の認可を提供します。セキュリティフィルターの 1 つとして FilterChainProxy に挿入されます。
SecurityFilterChain
を宣言するときに、デフォルトをオーバーライドできます。authorizeRequests
を使用する代わりに、次のように authorizeHttpRequests
を使用します。
Java
@Bean
SecurityFilterChain web(HttpSecurity http) throws AuthenticationException {
http
.authorizeHttpRequests((authorize) -> authorize
.anyRequest().authenticated();
)
// ...
return http.build();
}
これにより、authorizeRequests
がいくつかの点で改善されます。
メタデータソース、構成属性、意思決定マネージャー、投票者の代わりに、簡略化された
AuthorizationManager
API を使用します。これにより、再利用とカスタマイズが簡単になります。Authentication
ルックアップを遅らせます。リクエストごとに認証を検索する必要はなく、認可の決定で認証が必要なリクエストでのみ認証が検索されます。Bean ベースの構成のサポート。
authorizeRequests
の代わりに authorizeHttpRequests
が使用される場合、FilterSecurityInterceptor
の代わりに AuthorizationFilter
(Javadoc) が使用されます。
まず、
AuthorizationFilter
は SecurityContextHolder から認証を取得します。ルックアップを遅らせるために、これをSupplier
でラップします。次に、
Supplier<Authentication>
とHttpServletRequest
をAuthorizationManager
に渡します。認可が拒否された場合、
AccessDeniedException
がスローされます。この場合、ExceptionTranslationFilter
はAccessDeniedException
を処理します。アクセスが許可されると、
AuthorizationFilter
は FilterChain を続行します。これにより、アプリケーションは正常に処理できます。
Spring Security を構成して、優先順位の高いルールを追加することで、異なるルールを設定できます。
Java
@Bean
SecurityFilterChain web(HttpSecurity http) throws Exception {
http
// ...
.authorizeHttpRequests(authorize -> authorize (1)
.requestMatchers("/resources/**", "/signup", "/about").permitAll() (2)
.requestMatchers("/admin/**").hasRole("ADMIN") (3)
.requestMatchers("/db/**").access(new WebExpressionAuthorizationManager("hasRole('ADMIN') and hasRole('DBA')")) (4)
// .requestMatchers("/db/**").access(AuthorizationManagers.allOf(AuthorityAuthorizationManager.hasRole("ADMIN"), AuthorityAuthorizationManager.hasRole("DBA"))) (5)
.anyRequest().denyAll() (6)
);
return http.build();
}
1 | 複数の認可ルールが指定されています。各ルールは、宣言された順序で考慮されます。 |
2 | すべてのユーザーがアクセスできる複数の URL パターンを指定しました。具体的には、URL が "/resources/" で始まるか、"/signup" に等しいか、"/about" に等しい場合、すべてのユーザーがリクエストにアクセスできます。 |
3 | "/admin/" で始まる URL は、"ROLE_ADMIN" のロールを持つユーザーに制限されます。hasRole メソッドを呼び出しているため、"ROLE_" プレフィックスを指定する必要がないことに気付くでしょう。 |
4 | "/db/" で始まる URL には、ユーザーが "ROLE_ADMIN" と "ROLE_DBA" の両方を持っている必要があります。hasRole 式を使用しているため、"ROLE_" プレフィックスを指定する必要がないことに気付くでしょう。 |
5 | 4 からの同じルールは、複数の AuthorizationManager を組み合わせて書くことができます。 |
6 | まだ一致していない URL はアクセスを拒否されます。これは、認可規則の更新を誤って忘れたくない場合に適した戦略です。 |
次のように独自の RequestMatcherDelegatingAuthorizationManager
を構築することにより、Bean ベースのアプローチをとることができます。
Java
@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) {
MvcRequestMatcher.Builder mvcMatcherBuilder = new MvcRequestMatcher.Builder(introspector);
RequestMatcher permitAll =
new AndRequestMatcher(
mvcMatcherBuilder.pattern("/resources/**"),
mvcMatcherBuilder.pattern("/signup"),
mvcMatcherBuilder.pattern("/about"));
RequestMatcher admin = mvcMatcherBuilder.pattern("/admin/**");
RequestMatcher db = mvcMatcherBuilder.pattern("/db/**");
RequestMatcher any = AnyRequestMatcher.INSTANCE;
AuthorizationManager<HttpServletRequest> 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());
}
リクエストマッチャーに対して独自のカスタム認証マネージャーを接続することもできます。
Java
@Bean
SecurityFilterChain web(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((authorize) -> authorize
.requestMatchers("/my/authorized/endpoint").access(new CustomAuthorizationManager());
)
// ...
return http.build();
}
または、以下に示すように、すべてのリクエストに提供できます。
Java
@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 を設定できます。
Java
Kotlin
@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()
}
これで、すべてのディスパッチャー型に適用される認可ルールにより、それらの認可をより詳細に制御できるようになりました。例: shouldFilterAllDispatcherTypes
を true
に構成したいが、ディスパッチャー型 ASYNC
または FORWARD
のリクエストには認可を適用したくない場合があります。
Java
Kotlin
@Bean
SecurityFilterChain web(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((authorize) -> authorize
.shouldFilterAllDispatcherTypes(true)
.dispatcherTypeMatchers(DispatcherType.ASYNC, DispatcherType.FORWARD).permitAll()
.anyRequest().authenticated()
)
// ...
return http.build();
}
@Bean
open fun web(http: HttpSecurity): SecurityFilterChain {
http {
authorizeHttpRequests {
shouldFilterAllDispatcherTypes = true
authorize(DispatcherTypeRequestMatcher(DispatcherType.ASYNC, DispatcherType.FORWARD), permitAll)
authorize(anyRequest, authenticated)
}
}
return http.build()
}
ディスパッチャー型に特定のロールを要求するようにカスタマイズすることもできます。
Java
Kotlin
@Bean
SecurityFilterChain web(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((authorize) -> authorize
.shouldFilterAllDispatcherTypes(true)
.dispatcherTypeMatchers(DispatcherType.ERROR).hasRole("ADMIN")
.anyRequest().authenticated()
)
// ...
return http.build();
}
@Bean
open fun web(http: HttpSecurity): SecurityFilterChain {
http {
authorizeHttpRequests {
shouldFilterAllDispatcherTypes = true
authorize(DispatcherTypeRequestMatcher(DispatcherType.ERROR), hasRole("ADMIN"))
authorize(anyRequest, authenticated)
}
}
return http.build()
}
リクエストマッチャー
RequestMatcher
インターフェースは、リクエストが特定のルールに一致するかどうかを判断するために使用されます。securityMatchers
を使用して、特定の HttpSecurity
を特定のリクエストに適用する必要があるかどうかを判断します。同様に、requestMatchers
を使用して、特定のリクエストに適用する必要がある認可規則を決定できます。次の例を参照してください。
Java
Kotlin
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.securityMatcher("/api/**") (1)
.authorizeHttpRequests(authorize -> authorize
.requestMatchers("/user/**").hasRole("USER") (2)
.requestMatchers("/admin/**").hasRole("ADMIN") (3)
.anyRequest().authenticated() (4)
)
.formLogin(withDefaults());
return http.build();
}
}
@Configuration
@EnableWebSecurity
open class SecurityConfig {
@Bean
open fun web(http: HttpSecurity): SecurityFilterChain {
http {
securityMatcher("/api/**") (1)
authorizeHttpRequests {
authorize("/user/**", hasRole("USER")) (2)
authorize("/admin/**", hasRole("ADMIN")) (3)
authorize(anyRequest, authenticated) (4)
}
}
return http.build()
}
}
1 | /api/ で始まる URL にのみ適用されるように HttpSecurity を構成する |
2 | USER ロールを持つユーザーに /user/ で始まる URL へのアクセスを許可する |
3 | ADMIN ロールを持つユーザーに /admin/ で始まる URL へのアクセスを許可する |
4 | 上記のルールに一致しないその他のリクエストには、認証が必要です |
securityMatcher(s)
および requestMatcher(s)
メソッドは、アプリケーションに最適な RequestMatcher
実装を決定します。Spring MVC がクラスパスにある場合は MvcRequestMatcher
が使用され、それ以外の場合は AntPathRequestMatcher
が使用されます。Spring MVC 統合の詳細については、こちらを参照してください。
特定の RequestMatcher
を使用したい場合は、実装を securityMatcher
および / または requestMatcher
メソッドに渡すだけです:
Java
Kotlin
import static org.springframework.security.web.util.matcher.AntPathRequestMatcher.antMatcher; (1)
import static org.springframework.security.web.util.matcher.RegexRequestMatcher.regexMatcher;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.securityMatcher(antMatcher("/api/**")) (2)
.authorizeHttpRequests(authorize -> authorize
.requestMatchers(antMatcher("/user/**")).hasRole("USER") (3)
.requestMatchers(regexMatcher("/admin/.*")).hasRole("ADMIN") (4)
.requestMatchers(new MyCustomRequestMatcher()).hasRole("SUPERVISOR") (5)
.anyRequest().authenticated()
)
.formLogin(withDefaults());
return http.build();
}
}
public class MyCustomRequestMatcher implements RequestMatcher {
@Override
public boolean matches(HttpServletRequest request) {
// ...
}
}
import org.springframework.security.web.util.matcher.AntPathRequestMatcher.antMatcher (1)
import org.springframework.security.web.util.matcher.RegexRequestMatcher.regexMatcher
@Configuration
@EnableWebSecurity
open class SecurityConfig {
@Bean
open fun web(http: HttpSecurity): SecurityFilterChain {
http {
securityMatcher(antMatcher("/api/**")) (2)
authorizeHttpRequests {
authorize(antMatcher("/user/**"), hasRole("USER")) (3)
authorize(regexMatcher("/admin/**"), hasRole("ADMIN")) (4)
authorize(MyCustomRequestMatcher(), hasRole("SUPERVISOR")) (5)
authorize(anyRequest, authenticated)
}
}
return http.build()
}
}
1 | AntPathRequestMatcher および RegexRequestMatcher から静的ファクトリメソッドをインポートして、RequestMatcher インスタンスを作成します。 |
2 | AntPathRequestMatcher を使用して、/api/ で始まる URL にのみ適用されるように HttpSecurity を構成します。 |
3 | AntPathRequestMatcher を使用して、USER ロールを持つユーザーに /user/ で始まる URL へのアクセスを許可する |
4 | RegexRequestMatcher を使用して、ADMIN ロールを持つユーザーに /admin/ で始まる URL へのアクセスを許可する |
5 | カスタム RequestMatcher を使用して、SUPERVISOR ロールを持つユーザーに MyCustomRequestMatcher に一致する URL へのアクセスを許可します |
式
SpEL の代わりに型 セーフな認可マネージャーを使用することをお勧めします。ただし、レガシー SpEL の移行に役立つ WebExpressionAuthorizationManager
を利用できます。
WebExpressionAuthorizationManager
を使用するには、次のように、移行しようとしている式を使用して作成できます。
Java
Kotlin
.requestMatchers("/test/**").access(new WebExpressionAuthorizationManager("hasRole('ADMIN') && hasRole('USER')"))
.requestMatchers("/test/**").access(WebExpressionAuthorizationManager("hasRole('ADMIN') && hasRole('USER')"))
@webSecurity.check(authentication, request)
のように式で Bean を参照している場合は、代わりに Bean を直接呼び出すことをお勧めします。これは次のようになります。
Java
Kotlin
.requestMatchers("/test/**").access((authentication, context) ->
new AuthorizationDecision(webSecurity.check(authentication.get(), context.getRequest())))
.requestMatchers("/test/**").access((authentication, context): AuthorizationManager<RequestAuthorizationContext> ->
AuthorizationDecision(webSecurity.check(authentication.get(), context.getRequest())))
Bean 参照やその他の式を含む複雑な命令については、変更して AuthorizationManager
を実装し、.access(AuthorizationManager)
を呼び出して参照することをお勧めします。
それができない場合は、Bean リゾルバーを使用して DefaultHttpSecurityExpressionHandler
を構成し、それを WebExpressionAuthorizationManager#setExpressionhandler
に提供できます。