Spring Security入門|認証 / 認可の基本をやさしく解説

Spring BootでAPIやWebアプリを作っていると、どこかで必ず気になってくるのがセキュリティです。

ログインが必要な画面をどう守るのか。
管理者だけ使える機能をどう制御するのか。
そもそも、未ログインのユーザーが来たときに何を返せばいいのか。

このあたりは後回しにしようと思っても、アプリが少し形になってくると避けて通れません。
ただ、Spring Securityは最初の印象が少し重くて、設定クラスや見慣れないメソッドが出てきたところで手が止まりやすいです。

Spring Securityは、Springベースのアプリに対して 認証認可一般的な攻撃への保護 を提供するフレームワークです。Spring Securityの公式リファレンスでも、その役割は authentication、authorization、protection against common attacks と整理されています。

この記事では、Spring Securityの役割と基本設定を、入門向けに整理します。
OAuth2やJWTの詳細までは広げず、まずは Spring Securityが何をしていて、最初にどこを触ればいいのか が分かるところまでを目標にします。

目次

Spring Securityでできること

ここでは、Spring Securityが何のために入るのかを整理します。

Spring Securityが必要になる場面

Spring Securityが必要になるのは、単にログイン画面を作るときだけではありません。

たとえば、次のような場面で役立ちます。

  • ログイン済みユーザーだけが使えるページを作りたい
  • 管理者だけが使えるURLを分けたい
  • APIに対して未認証アクセスを防ぎたい
  • CSRFのような攻撃への対策を入れたい

Spring Securityは、Servletベースのアプリケーションではフィルターを中心にリクエストを保護します。Spring Securityのアーキテクチャ説明でも、Servlet Filter を基盤としてセキュリティ処理が行われる構成が示されています。

つまり、Controllerの中で毎回「このユーザーは使っていいか」を判定するというより、リクエストがアプリに届く手前で整理する のが基本です。

認証と認可の違い

Spring Securityを理解するうえで、まず分けて考えたいのが 認証認可 です。

  • 認証
    そのユーザーが誰なのかを確認すること
  • 認可
    そのユーザーに何を許可するかを決めること

たとえば、ログイン画面でIDとパスワードを確認するのは認証です。
そのあとに「管理画面は管理者だけ」という制御をするのが認可です。

この2つが頭の中で混ざると、設定を読んだときに分かりにくくなります。
最初は、ログイン確認が認証、アクセス権限の判定が認可 と切り分けて考えるとかなり整理しやすいです。

Spring Securityの全体像

Spring Securityは、かなり多機能です。
ただ、入門の時点で全部を理解する必要はありません。

最初に押さえたいのは次の3つです。

  • どのURLにアクセスを許可するか
  • どんな方法でログインさせるか
  • 未ログインや権限不足のときにどう扱うか

Spring BootでSpring Securityをクラスパスに入れると、Webアプリケーションはデフォルトで保護されます。また、Spring Bootはコンテンツネゴシエーションに応じて httpBasic または formLogin を使い分けます。

最初はこの挙動に驚きますが、逆にいえば 何も考えなくても最低限の保護がかかる ところがSpring Securityの入口でもあります。

まず押さえたい基本設定

ここでは、Spring Securityを使い始めるときに最初に触る部分を見ていきます。

依存関係の追加

まず必要なのは、Spring Securityの依存関係です。

Spring Bootでは、通常 spring-boot-starter-security を追加して導入します。Spring Bootの公式リファレンスでも、Spring Securityがクラスパス上にあるとWebアプリはデフォルトで保護されると案内されています。

Mavenなら次のように追加します。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

Gradleならこちらです。

implementation 'org.springframework.boot:spring-boot-starter-security'

Spring Initializrで作成したプロジェクトでは、最初から追加されていることもあります。
動きが想定と違うときは、まず依存関係が入っているかを確認すると切り分けしやすいです。

何も設定しないとどうなるか

Spring Securityを追加すると、何も設定を書かなくてもWebアプリは保護されます。Spring Bootの公式ドキュメントでは、/error を含むWebアプリケーションのエンドポイントがデフォルトで保護されると説明されています。

そのため、最初に起きやすいのは次のような状況です。

  • すべてのURLに認証が必要になる
  • ブラウザでアクセスするとログイン画面が出る
  • APIクライアントでアクセスすると401系の応答になる

この「急に守られた感じ」が最初の壁になりやすいです。
ただ、これは壊れているのではなく、セキュリティが有効になった結果 です。

SecurityFilterChain の役割

今のSpring Securityで基本となる設定は、SecurityFilterChain をBeanとして定義する形です。Spring SecurityのJava Configurationでは、springSecurityFilterChain がアプリケーションURLの保護、ログイン処理、ユーザー名とパスワードの検証などを担うと説明されています。

基本形は次のようになります。

package com.example.demo.security;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
                .authorizeHttpRequests(auth -> auth
                        .requestMatchers("/", "/login", "/css/**").permitAll()
                        .anyRequest().authenticated()
                )
                .formLogin(Customizer.withDefaults());

        return http.build();
    }
}

この設定で見ていることはそこまで多くありません。

  • //login などは誰でもアクセス可能
  • それ以外は認証が必要
  • ログイン方法はフォームログインを使う

最初はこのくらいの設定から始めるのが分かりやすいです。

リクエストごとのアクセス制御

ここでは、どのURLを誰に許可するかを見ます。

authorizeHttpRequests の基本

URL単位のアクセス制御では、authorizeHttpRequests を使うのが基本です。Spring Securityの公式ドキュメントでも、リクエスト単位の認可をこの方法でモデル化できると説明されています。さらに、HttpSecurity を使う場合は認可ルールを宣言する必要があるとも案内されています。

たとえば、次のように書けます。

http
    .authorizeHttpRequests(auth -> auth
        .requestMatchers("/", "/about").permitAll()
        .requestMatchers("/admin/**").hasRole("ADMIN")
        .anyRequest().authenticated()
    );

意味はかなり素直です。

  • トップページや紹介ページは誰でも見られる
  • /admin/** は管理者だけ
  • それ以外はログインが必要

最初は requestMatchersanyRequest の流れだけ分かれば十分です。

permitAll / authenticated の使い分け

入門でよく出てくるのが permitAll()authenticated() です。

  • permitAll()
    認証なしでもアクセスできる
  • authenticated()
    ログイン済みユーザーだけアクセスできる

この違いはシンプルですが、かなり大事です。
ログインページやCSS、画像などまで認証必須にしてしまうと、画面が崩れたりログイン導線が壊れたりします。

そのため、最初の設定では 公開するもの守るもの を素直に分けることが重要です。

URL単位で制御するときの考え方

URL単位の認可は分かりやすい一方で、ルールが散らかりやすい面もあります。

たとえば、画面が増えるたびに場当たり的に requestMatchers を追加していくと、後から見たときに「どこが公開で、どこが保護なのか」が分かりにくくなります。

最初のうちは、次のように整理しておくと見通しがよくなります。

  • 公開ページ
  • ログイン必須ページ
  • 管理者向けページ

この粒度で分けておくと、入門段階でもかなり迷いにくいです。

認証の基本

ここでは、ログインをどう扱うのかを見ていきます。

formLogin と httpBasic の違い

Spring Securityの入門でよく見るのが formLoginhttpBasic です。

  • formLogin
    HTMLのログイン画面を使った認証
  • httpBasic
    HTTP Basic認証を使ったシンプルな認証

Spring Securityの公式ドキュメントでは、フォームログインはHTMLフォーム経由のユーザー名 / パスワード入力を扱い、HTTP BasicはHTTPレベルのBasic認証を扱うと説明されています。

フォーム画面を持つWebアプリなら、まず formLogin が分かりやすいです。
一方で、簡単なAPI確認や内部ツールでは httpBasic が手軽に感じることもあります。

ログインの流れをざっくり理解する

ログインの内部ではいろいろな処理が走っていますが、最初はざっくりで十分です。

フォームログインなら、おおまかには次の流れです。

  1. 未認証のまま保護されたURLにアクセスする
  2. ログイン画面へリダイレクトされる
  3. ユーザー名とパスワードを送信する
  4. 認証に成功したら元の処理へ進める

Spring Securityのフォームログイン説明でも、未認証リクエストからログイン画面へのリダイレクト、認証処理の流れが図とともに説明されています。

内部のフィルターやマネージャーまで最初から追うと重いですが、未認証ならログインへ、成功したら先へ進む と理解できれば十分入口に立てます。

認証エラー時に何が起きるか

認証に失敗したときの動きも、アプリの種類によって見え方が変わります。

ブラウザ中心のアプリでは、ログイン画面に戻されたり、エラーメッセージが出たりします。
HTTP Basicでは、WWW-Authenticate ヘッダー付きで未認証応答が返る流れが公式ドキュメントで説明されています。

ここで大事なのは、未認証権限不足 は同じではないことです。
ログインしていないのか、ログインはしているけれど許可がないのかで、考え方が変わります。

この違いは、例外処理の記事ともつながりやすいところです。

よく出てくる周辺知識

ここでは、入門の段階で最低限知っておくと混乱しにくい話を整理します。

CSRFをどう考えるか

Spring Securityを使い始めると、CSRFという言葉をよく見かけます。

CSRFは、ユーザーが意図しないリクエストを別サイト経由で送らされる攻撃です。Spring Securityは、ログインを伴うアプリケーションでは unsafe HTTP methods、たとえば POST に対してデフォルトでCSRF保護を有効にしています。

このあたりで混乱しやすいのは、「とりあえず無効化すればいいのか」という点です。
たしかに開発初期では csrf(csrf -> csrf.disable()) を見かけることがありますが、何のために無効化するのかを理解しないまま入れると、後から判断しにくくなります。

画面を持つ通常のWebアプリでは、まず CSRFはデフォルトで守られるもの と考えておくほうが自然です。

セッション管理の基本

Spring Securityでは、デフォルトで SecurityContext をHTTPセッションに保存します。公式ドキュメントでも、デフォルトではHTTPセッションにセキュリティコンテキストを保存すると説明されています。

つまり、フォームログイン中心のアプリでは、ログイン状態はセッションと一緒に扱われるのが基本です。

このあたりを知らないままAPIの感覚で見ていると、「なんでログイン状態が続いているんだろう」と感じやすくなります。
逆にいえば、最初は フォームログインならセッション管理が基本 と覚えておくと理解しやすいです。

API開発で最初に意識したいこと

API開発でもSpring Securityは使えますが、画面ありのWebアプリと同じ感覚で設定すると戸惑いやすいです。

特に最初に意識したいのは次の点です。

  • ブラウザ向けのログイン画面が本当に必要か
  • Basic認証で足りるのか
  • セッション前提でよいのか
  • CSRFをどう考えるか

ここでJWTやOAuth2まで一気に広げると、入門記事としては重くなります。
まずは 今のアプリが画面中心なのか、API中心なのか を意識するだけでも設定の見え方がかなり変わります。

よくあるつまずき

ここでは、最初にハマりやすいところをまとめます。

すべてのURLに認証がかかって困る

これはかなりよくある最初のつまずきです。

Spring BootでSpring Securityを入れると、デフォルトでWebアプリが保護されるため、設定を書いていないと「全部ログイン必須」に見えやすいです。

この場合は、まず permitAll() を付けるべきURLを整理します。
トップページ、ログインページ、静的ファイルなど、公開したいものを明示するだけでもかなり分かりやすくなります。

ログイン画面が急に出てきて驚く

ブラウザでアクセスしたら、急にSpring Securityのログイン画面が出てくることがあります。

これは異常ではなく、Spring Bootがコンテンツネゴシエーションに応じて formLoginhttpBasic を使い分けるためです。ブラウザアクセスではフォームログインの流れが見えやすくなります。

最初はびっくりしますが、むしろ 今はSpring Securityが有効になっている と確認しやすい挙動でもあります。

permitAll を付けたのに想定どおり動かない

これも地味によくあります。

原因はいくつかありますが、まず確認したいのは次のような点です。

  • 対象URLのパターンが合っているか
  • 静的ファイルのパスを見落としていないか
  • そもそも別のURLにリダイレクトされていないか

特にCSSやJavaScriptまで認証対象になっていると、画面自体は表示されても見た目が崩れて原因が分かりづらくなります。
まずは どのURLを公開して、どのURLを守るのか を整理し直すのが近道です。

まとめ

Spring Securityは最初こそ重たく見えますが、入門の段階で本当に押さえたいことはそこまで多くありません。

まずは、次の流れを理解できれば十分です。

  • Spring Securityは 認証 / 認可 / 一般的な攻撃への保護 を担う
  • Spring Bootに追加すると、Webアプリはデフォルトで保護される
  • SecurityFilterChain でURLごとのルールやログイン方法を設定する
  • permitAll()authenticated() の違いを押さえる
  • フォームログイン、HTTP Basic、CSRF、セッションの基本をざっくり理解する

最初からOAuth2やJWTまで追いかけなくても大丈夫です。
まずは 公開するURLと守るURLを分けられることログインの流れをざっくり説明できること が入口としてかなり大きいです。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

コメント

コメントする

CAPTCHA


目次