0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【学習記録】Spring Boot + Spring Security でログイン機能を作る 【SpringBoot】

0
Last updated at Posted at 2026-03-03

今日のテーマ

秀和システムのSpringBoot3プログラミング入門を用いて学習中です。

Spring Bootの学習としてSpring Securityによる認証機能を実装しました。
セットアップでつまずいた部分も多かったので、同じ初学者の参考になればと思います。

環境

  • macOS
  • Cursor
  • Java 17
  • Spring Boot 3.5.x
  • Gradle

1. プロジェクトの作成(Spring Initializr)

Spring Initializr にアクセスしてプロジェクトを作成する。

設定内容

項目 設定値
Project Gradle - Groovy
Language Java
Spring Boot 3.x.x
Group com.example
Artifact samplesecurityapp
Packaging Jar
Java 17

設定が完了したら「GENERATE」ボタンをクリックするとzipファイルがダウンロードされる。解凍してCursorで開けばすぐに開発が始められる。

2. build.gradle の依存関係

Spring Initializrでプロジェクトを作成する際、以下の依存関係を追加しておく必要がある。
これがないとWebアプリとして起動しない。

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.boot:spring-boot-starter-security'
    implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
    implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity6'
    implementation 'org.springframework.boot:spring-boot-starter-data-jdbc'
    runtimeOnly 'com.h2database:h2'
    runtimeOnly 'com.mysql:mysql-connector-j'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    testImplementation 'org.springframework.security:spring-security-test'
    testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}

各依存関係の役割

Spring Initializrでの名前 build.gradleでの名前 用途
Spring Web spring-boot-starter-web WebアプリのHTTP機能
Thymeleaf spring-boot-starter-thymeleaf HTMLテンプレートエンジン
Spring Security spring-boot-starter-security ログイン・認証機能
Spring Data JDBC spring-boot-starter-data-jdbc DBアクセス機能
H2 Database h2 インメモリDB(開発用)
MySQL Driver mysql-connector-j MySQLドライバ

※使用中の書籍ではこの部分についての記載はなく、追加を必要としない(元々入っている?)ようだったので、バージョンの違いや私の操作ミスなどにより追加が必要になった可能性を否定しきれません。


3. アプリの起動

依存関係を変更したあとは必ず clean してから起動する。

./gradlew clean bootRun

通常の起動はこちらでOK

./gradlew bootRun

起動に成功すると以下のログが出る。

Tomcat started on port 8080
Using generated security password: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

4. Spring Security の設定

SampleSecurityConfig.java でセキュリティの設定を行う。

@Configuration
@EnableWebSecurity
public class SampleSecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.csrf(csrf -> csrf.disable());
        http.authorizeHttpRequests(authorize -> {
            authorize
                .requestMatchers("/").permitAll()       // "/" は誰でもOK
                .requestMatchers("/js/**").permitAll()  // /js/ 以下は誰でもOK
                .requestMatchers("/css/**").permitAll() // /css/ 以下は誰でもOK
                .requestMatchers("/img/**").permitAll() // /img/ 以下は誰でもOK
                .anyRequest().authenticated();          // 上記以外のすべてはログイン必須
        });
        http.formLogin(form -> {
            form.defaultSuccessUrl("/secret");
        });
        return http.build();
    }
}

ポイント

authorizeHttpRequests
URLごとのアクセス制御を設定する。

  • .permitAll() → ログイン不要でアクセス可
  • .authenticated() → ログインが必要

個別に指定したURL以外のすべてに対するルールが anyRequest()
必ず一番最後に書くというルールがある。

ルールは上から順番に評価されるので、anyRequest() が先にあると「すべて」にマッチしてしまい、後ろの個別ルールが意味をなさなくなります。

formLogin
ログインフォームの設定。

  • defaultSuccessUrl("/secret") → ログイン成功後のデフォルト遷移先

defaultSuccessUrl の第2引数に true を渡すと常に指定URLへ遷移、false(デフォルト)は元々アクセスしようとしていたページを優先する。

csrf

http.csrf(csrf -> csrf.disable());

↑この部分について、書籍では下記でした。推奨されないと警告が出ていたので書き換えています。

http.csrf().disable()

Spring Boot 3系(Spring Security 6)では http.csrf().disable() は非推奨。
ラムダ式を使った書き方にする。


5. ラムダ式とは

Spring Boot 3系ではラムダ式(->)が多用される。

http.formLogin(form -> {
    form.defaultSuccessUrl("/secret");
});

-> の左側が「受け取る引数」、右側が「やること(処理)」。
「設定を渡す」場面でよく登場する。


6. Spring Security の動作の流れ

/secret にログインせずにアクセスすると、自動でログイン画面にリダイレクトされる。
これがSpring Securityが自動でやってくれていること。コントローラーに認証チェックのコードを書く必要はない。

ブラウザで /secret にアクセス
        ↓
Spring Security が「ログインしてる?」を自動チェック
        ↓
未ログイン → /login に自動リダイレクト
ログイン済み → /secret を表示

7. MVCの流れ

Webアプリは MVC(Model-View-Controller) という設計パターンで動く。

ブラウザが / にアクセス
        ↓
Controller がデータ(Model)と画面名(View)をセット
        ↓
Thymeleaf が HTML に ${title} などの形でデータを埋め込む
        ↓
完成したHTMLをブラウザに返す

Controller のコード

@RequestMapping("/")
public ModelAndView index(ModelAndView mav) {
    mav.setViewName("index");               // 表示するHTMLファイル名
    mav.addObject("title", "Index Page");   // HTMLに渡すデータ
    mav.addObject("msg", "This is top page.");
    return mav;
}

mav の型は ModelAndView です。名前を分解すると:
Model = データ(addObject で追加したもの 例:title, msg)
View = 画面(setViewName で指定したもの 例:index.html)

  • ModelAndView = Model(データ)+ View(画面)をセットにしたもの
  • setViewName("index")templates/index.html を表示
  • addObject("title", "Index Page") → HTML内の ${title} に値が入る

Thymeleaf(HTML側)

<h1 th:text="${title}"></h1>
<p th:text="${msg}"></p>

${title} の部分にControllerから渡された値が埋め込まれてブラウザに表示される。


8. 全体の流れまとめ

① ブラウザでアクセス
        ↓
② Spring Security が「ログインしてる?」と確認
        ↓
③ してなければ → ログイン画面へリダイレクト
        ↓
④ ユーザー名・パスワードを入力してログイン
        ↓
⑤ Controller がデータと画面名をセットして返す(MVC)
        ↓
⑥ Thymeleaf が HTML にデータを埋め込む
        ↓
⑦ ブラウザに画面が表示される

Spring Security・Java文法・MVCはバラバラに存在しているのではなく、この一本の流れの中でそれぞれが役割を持っている。


つまずきポイント

ラムダ式の引数名のミス

// NG: 引数名を formLogin にしたのに、中で form と使ってしまった
http.formLogin(formLogin -> {
    form.defaultSuccessUrl("/secret"); // エラー: シンボルを見つけられません
});

// OK: 引数名と中で使う名前を一致させる
http.formLogin(form -> {
    form.defaultSuccessUrl("/secret");
});

引数名は自分で自由につけられる。-> の左側の名前と右側で使う名前を一致させる。

依存関係追加後は clean が必要

build.gradle を変更したあとにそのまま bootRun すると古いキャッシュで動いてしまうことがある。

./gradlew clean bootRun

重ねてになりますが、自分がこれはどういうこと?とAIに質問したことを中心に、きっと同じように感じる人もいるはず!という気持ちと、忘備録を兼ねて記事にしています。
教科書的な記事ではないので、私が気にならずスルーしていることもあるかもしれません。
何かあったら教えていただけますとありがたいです。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?