1. URL だけでの認可分岐(通常の方法)
requestMatchers() は URL や HTTP メソッド(GET、POSTなど)に対するマッチング専用で、HTTP ヘッダーの値を直接見ることはできません。
例1
URLパターン
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/public/**").permitAll()
.requestMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
);
例2
httpメソッドとURLパターン
http
.authorizeHttpRequests(auth -> auth
.requestMatchers(HttpMethod.GET, "/api/public/**").permitAll()
.requestMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
);
2. HTTP ヘッダーの値で認可を分岐したい場合
これは以下のようにカスタム OncePerRequestFilter
を使うことで実現可能です。
例:特定ヘッダー(例: X-API-KEY
)の有無で認証をスキップまたは適用
① カスタムフィルターの実装
public class HeaderBasedAuthBypassFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain)
throws ServletException, IOException {
String path = request.getRequestURI();
String apiKey = request.getHeader("X-API-KEY");
if (path.startsWith("/external/") && "skip-auth".equals(apiKey)) {
// 認可対象外にしたい場合
SecurityContextHolder.clearContext();
}
filterChain.doFilter(request, response);
}
}
② SecurityFilterChain に登録
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.addFilterBefore(new HeaderBasedAuthBypassFilter(),
UsernamePasswordAuthenticationFilter.class) // (1)
.authorizeHttpRequests(auth -> auth
.requestMatchers("/external/**").permitAll() // フィルターで認可制御
.anyRequest().authenticated()
);
return http.build();
}
// (1)
addFilterBeforeは、第1引数に指定したフィルタークラスを第2引数に指定したフィルタークラスより前で動かします。
早い段階で全リクエストを捕まえたい(URL・ヘッダー分岐など)。 認証前(SecurityContextHolder も未初期化)
→ SecurityContextPersistenceFilter.class をaddFilterBeforeの第2引数指定
JWT の検証など、認証処理の前にチェックしたい。認証はされていないが、SecurityContext は初期化済み
→ UsernamePasswordAuthenticationFilter.class をaddFilterBeforeの第2引数指定
すでに認証が済んでいる前提で認可ロジックに関与したい
→ FilterSecurityInterceptor.class をaddFilterBeforeの第2引数指定
HTTP Basic 認証より前
→ BasicAuthenticationFilter.class をaddFilterBeforeの第2引数指定
3. より柔軟な条件分岐にしたい場合
- Spring Expression Language(SpEL)を
access()
に使う方法もありますが、ヘッダーには直接アクセスできません。 - よって、カスタム
AuthorizationManager
を使う方法もあります(より高度なケース)。
まとめ
条件 | 方法 |
---|---|
URL パターンで分岐 |
requestMatchers() を使う |
ヘッダーの値で分岐 |
OncePerRequestFilter などのカスタムフィルターを挿入 |
URL + ヘッダーの複合分岐 | カスタムフィルターで両方の条件を判定して、SecurityContext を調整 |