Spring Securityでページごとにアクセス制限をかける方法を徹底解説!初心者向けにやさしく解説
新人
「Spring Securityでページごとにアクセス制限をかけるってどういう意味なんですか?」
先輩
「例えば、ログインしていない人が/adminのページを見られないようにしたり、管理者だけが特定のURLにアクセスできるようにする制御のことだよ。」
新人
「なるほど!でも、どうやってそれを設定するんですか?」
先輩
「Spring Securityの機能を使えば、URLごとにアクセス権限を制御できるんだ。まずは基本的な考え方から見てみよう!」
1. ページごとのアクセス制限とは?
「ページごとのアクセス制限」とは、特定のURLやWebページに対して、誰がアクセスできるかを制限する仕組みのことです。たとえば、次のようなケースがあります。
- ログインしていない人は
/mypageにアクセスできないようにする - 一般ユーザーは
/adminにアクセスできないようにする - 特定のロールを持つユーザーだけが
/settingsを操作できるようにする
企業の業務システムやECサイト、会員制サービスなどでは、セキュリティ上とても重要な機能です。認可のないアクセスをブロックすることで、情報漏えいや不正操作を防ぐことができます。
このようなページごとの制御は、Spring Securityというフレームワークを使えば、簡単に実現することができます。
2. Spring Securityでアクセス制限を実現する基本的な考え方
Spring Securityでページごとのアクセス制限をかけるには、「認証」と「認可」という2つの考え方を理解する必要があります。
■ 認証(Authentication)とは?
認証とは、「そのユーザーが誰であるか」を確認するプロセスのことです。ログインフォームにユーザー名とパスワードを入力し、正しく照合されたら認証が成功します。
つまり、「本人であることの確認」です。Spring Securityでは、ログインの設定をすることでこの認証処理を自動で行ってくれます。
■ 認可(Authorization)とは?
認可とは、「そのユーザーがどのページにアクセスしていいか」を決めるルールのことです。たとえば、ログインは成功していても、一般ユーザーが管理者専用のページにアクセスしようとした場合、それをブロックするのが認可の役割です。
Spring Securityでは、URLごとにアクセスできるロール(権限)を設定することで、この認可の仕組みを実装できます。
3. URLごとのアクセス制限を定義する方法
Spring Securityでアクセス制限を行うには、セキュリティ設定クラス(SecurityConfigなど)を作成して、そこにURLとアクセス権限を記述します。
以下は基本的な構成例です。
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authz -> authz
.requestMatchers("/admin/**").hasRole("ADMIN")
.requestMatchers("/user/**").hasAnyRole("USER", "ADMIN")
.requestMatchers("/public/**").permitAll()
.anyRequest().authenticated()
)
.formLogin(withDefaults())
.logout(withDefaults());
return http.build();
}
}
@Configurationと@EnableWebSecurityは、Spring Securityの設定クラスであることを示します。
requestMatchers("/admin/**").hasRole("ADMIN")の部分は、「/admin/で始まるすべてのURLにはADMINロールが必要」という意味です。
.anyRequest().authenticated()は、それ以外の全リクエストに対して「ログイン済みであること」を要求します。
4. ロール(ROLE_USER, ROLE_ADMINなど)によるアクセス制御の基本
Spring Securityでは、アクセス制限の設定において「ロール制御」が非常に重要です。ロールとは、ユーザーが持つ権限の名前のことです。例えば、一般ユーザーにはROLE_USER、管理者にはROLE_ADMINというような区別をします。
ロールを使うことで、「このページは管理者しか見られない」「この機能はユーザーなら使える」などの制御が簡単に実現できます。
Spring Securityでは、内部的にロール名にROLE_というプレフィックス(接頭語)を自動的に付けて処理します。そのため、設定ファイルではhasRole("ADMIN")と書けば、ROLE_ADMINとして扱われます。
次のコードは、ユーザー名によって異なるロールを設定して返す例です。
@Service
public class CustomUserDetailsService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
if ("admin".equals(username)) {
return User.builder()
.username("admin")
.password("{noop}adminpass")
.roles("ADMIN")
.build();
} else if ("user".equals(username)) {
return User.builder()
.username("user")
.password("{noop}userpass")
.roles("USER")
.build();
} else {
throw new UsernameNotFoundException("該当するユーザーが見つかりません");
}
}
}
このクラスは、Spring SecurityのUserDetailsServiceを実装して、ユーザー情報を定義しています。
「admin」というユーザー名でログインした場合は、ROLE_ADMINのロールを付与されます。
同様に、「user」というユーザー名ならROLE_USERが与えられます。
パスワードの前の{noop}は、パスワードをエンコードしない設定です。開発段階ではこの形式で問題ありませんが、本番環境では安全なエンコード方式にする必要があります。
このようにロールを使えば、Spring Securityで柔軟なアクセス制限の設定が可能になります。
5. セキュリティ設定ファイルでのページごとの制御方法(antMatchers)
Spring Securityでは、URLごとのアクセス制限の設定にantMatchers()というメソッドを使うことが多くあります。これは、リクエストされたURLに対して、どのロールがアクセス可能かを指定する方法です。
下記は、ページごとにロール制御を設定した例です。
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/user/**").hasAnyRole("USER", "ADMIN")
.antMatchers("/login", "/register", "/css/**").permitAll()
.anyRequest().authenticated()
)
.formLogin(form -> form
.loginPage("/login")
.defaultSuccessUrl("/home", true)
.permitAll()
)
.logout(logout -> logout
.logoutSuccessUrl("/login?logout")
.permitAll()
);
return http.build();
}
}
それぞれの設定内容を一文ずつ解説します。
.antMatchers("/admin/**").hasRole("ADMIN")⇒/admin以下のURLはROLE_ADMINを持つユーザーだけがアクセス可能になります。.antMatchers("/user/**").hasAnyRole("USER", "ADMIN")⇒ 一般ユーザーと管理者の両方がアクセスできます。.antMatchers("/login", "/register", "/css/**").permitAll()⇒ ログインページや新規登録ページ、CSSなどの静的リソースは誰でもアクセス可能とします。.anyRequest().authenticated()⇒ 上記に一致しない全てのURLはログインが必要です。.formLogin()⇒ カスタムログインページの設定です。ログイン成功後に/homeに遷移します。.logout()⇒ ログアウト後に/login?logoutにリダイレクトします。
このように、antMatchersを活用することで、Spring Securityのアクセス制限を細かく設定できます。
特に、ログインしていない状態でもアクセスできるページをpermitAll()で明示することで、ユーザー体験も向上します。
アクセス制限の設定を適切に行うことで、セキュリティを強化しつつ、使いやすいアプリケーションを構築することができます。
6. ログインユーザーのロールに応じて表示を切り替える方法
Spring Securityでは、ユーザーが持っているロールに応じて画面の表示内容を切り替えることができます。たとえば、管理者には「管理者メニュー」を、一般ユーザーには「ユーザーメニュー」を表示するように制御できます。
HTMLテンプレート内では、JSPやThymeleafのようなテンプレートエンジンを使って、Spring Securityのロールを判定できます。ここではJSPを例に解説します。
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>
<!-- 管理者ロールだけに表示されるメニュー -->
<sec:authorize access="hasRole('ROLE_ADMIN')">
<a href="/admin/dashboard">管理者ダッシュボード</a>
</sec:authorize>
<!-- 一般ユーザーに表示されるメニュー -->
<sec:authorize access="hasRole('ROLE_USER')">
<a href="/user/profile">プロフィール</a>
</sec:authorize>
<sec:authorize>タグは、Spring Securityが提供しているカスタムタグです。
hasRole('ROLE_ADMIN')のように指定することで、そのロールを持つユーザーだけにHTMLが表示されます。
このように、画面側でもロールによって表示を分岐させることで、より安全で直感的な操作性を実現できます。
ロールによる表示制御は、セキュリティ対策だけでなく、ユーザーごとの使いやすさ向上にも役立ちます。
7. ページアクセス制限の注意点と403エラーの扱い
Spring Securityでページごとのアクセス制限を設定した場合、次のような場面で注意が必要です。
まず、ユーザーがログインしていない状態で認証が必要なページにアクセスすると、ログインページにリダイレクトされます。これは自然な動作であり、ユーザー体験を損ねません。
しかし、ログイン済みでもアクセス権限が足りない場合には「403 Forbiddenエラー」が発生します。
このエラーは、「リクエストされたリソースにアクセスする権限がない」という意味です。
HTTP Status 403 – Forbidden
この403エラーは、Spring Securityが自動的に返しますが、ユーザーには「なぜ見られないのか」が分かりにくい場合があります。
そのため、カスタムの403エラーページを設定することが推奨されます。
以下は、403エラー時に表示するHTMLページの設定方法です。
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.antMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
)
.exceptionHandling(ex -> ex
.accessDeniedPage("/error/403") // 403エラーページを指定
)
.formLogin(withDefaults())
.logout(withDefaults());
return http.build();
}
}
.accessDeniedPage("/error/403")で、403エラー時に表示するページを指定しています。
このとき、指定されたパスに対応するコントローラとHTMLテンプレートも作成する必要があります。
@Controller
public class ErrorController {
@GetMapping("/error/403")
public String handle403() {
return "error403"; // resources/templates/error403.htmlなど
}
}
<!-- error403.html -->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>アクセス拒否</title>
</head>
<body>
<h1>403 - アクセスが拒否されました</h1>
<p>このページにアクセスする権限がありません。</p>
</body>
</html>
このようにカスタムエラーページを用意することで、403エラーが発生してもユーザーにとって分かりやすい画面を表示できます。
Spring Securityによるアクセス制限は便利ですが、403エラーなどの画面設計も丁寧に行うことが、実用的なアプリケーションには重要です。