Spring SecurityでURLごとのアクセス制御を実現する方法!requestMatcherと権限マッピングの設計
生徒
「Spring SecurityでURLごとにアクセス制御を設定したいんですが、どんな方法がありますか?」
先生
「Spring SecurityではrequestMatcherを使うと、URLパターンに応じた柔軟なアクセス制御ができますよ。また、ロール(権限)とのマッピングも重要です。」
生徒
「ロールのマッピングってどうやって設計するんですか?URLの設計との関係も気になります。」
先生
「それでは、URLごとのアクセス制御と、権限マッピング設計の基本から応用まで見ていきましょう!」
1. Spring SecurityでのURLアクセス制御とは
Spring Securityでは、ユーザーがアクセスできるページやエンドポイントを制限するために「URLごとのアクセス制御」を行います。特定のURLには特定の権限を持つユーザーしかアクセスできないように設定することで、不正アクセスを防ぎます。
URLのアクセス制御は、セキュリティ構成クラス内でauthorizeRequests()メソッドを使って実装されます。
2. requestMatcherの役割と使い方
requestMatcherは、HTTPリクエストに対して柔軟に条件を設定できるマッチャーです。たとえば、AntPathRequestMatcherやRegexRequestMatcherなどを使うことで、URLパターンやHTTPメソッドごとに細かくアクセス制御ができます。
http
.authorizeRequests()
.requestMatchers(new AntPathRequestMatcher("/admin/**"))
.hasRole("ADMIN")
.anyRequest()
.authenticated();
このように、/admin/以下のURLにはADMIN権限を持つユーザーしかアクセスできないように制御できます。
3. 権限(ロール)マッピングの設計パターン
アクセス制御を行うには、ユーザーの権限(ロール)とURLをどのようにマッピングするかを設計する必要があります。以下に一般的な設計例を示します。
/admin/**→ROLE_ADMIN/user/**→ROLE_USERまたはROLE_ADMIN/public/**→ 全ユーザー(認証不要)
このようにマッピングすることで、意図しないアクセスを防止しつつ、権限ごとに適切な操作だけを許可できます。
4. antMatchersとmvcMatchersの違い
requestMatcherの代わりに、antMatchersやmvcMatchersを使うケースもあります。それぞれの違いを理解しておくことも重要です。
- antMatchers:ワイルドカードでURLパターンを指定(例:
"/admin/**") - mvcMatchers:Spring MVCのURLマッピングに準拠し、プレフィックスなども考慮
http
.authorizeRequests()
.antMatchers("/admin/**")
.hasRole("ADMIN")
.antMatchers("/user/**")
.hasAnyRole("USER", "ADMIN")
.antMatchers("/public/**")
.permitAll();
5. 権限階層の設計と使い分け
実務では、「管理者はユーザーの機能も使えるが、その逆は不可」といった要件があります。このような場合には、権限の階層構造を意識してマッピングを行います。
例えば、以下のようにhasAnyRoleを使えば、複数のロールに対して許可が可能です。
http
.authorizeRequests()
.antMatchers("/dashboard")
.hasAnyRole("USER", "ADMIN");
6. リクエストメソッドによる制御
Spring Securityでは、URLだけでなく、HTTPメソッド(GET、POSTなど)に応じた制御も可能です。たとえば、RegexRequestMatcherを使うと、POSTメソッドのみにアクセスを制限できます。
http
.authorizeRequests()
.requestMatchers(new RegexRequestMatcher("/api/data", "POST"))
.hasRole("ADMIN");
7. 実務での設計ポイントと注意点
実際にURLごとのアクセス制御を設計する際は、以下のようなポイントに注意しましょう。
- URLの命名規則を明確にして、権限設計と合わせる
- 権限の粒度を粗すぎず細かすぎず設計する
- 不正アクセス対策として、デフォルトは
authenticated()にして、明示的にpermitAll()を使う
また、URLの設計ミスにより意図しないアクセスが許可されてしまうケースもあるため、定期的なレビューが重要です。
8. 認可エラー時のハンドリング設定
権限がないユーザーが制限されたURLにアクセスした際の挙動もカスタマイズできます。たとえば、403エラーページを指定する方法です。
http
.exceptionHandling()
.accessDeniedPage("/error/403");
9. セキュリティ設定の全体構成例
最後に、URLごとのアクセス制御、リクエストマッチャー、ロールマッピングなどを組み合わせた全体構成例を紹介します。
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/public/**").permitAll()
.antMatchers("/user/**").hasAnyRole("USER", "ADMIN")
.antMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll()
.and()
.exceptionHandling()
.accessDeniedPage("/error/403");
}
}
このように構成することで、URLごとに適切なセキュリティルールを適用し、権限のあるユーザーだけがアクセスできるようになります。