用語
■ SpringSecurity:
Spring Securityは、Springベースのアプリケーションに、認証 (BASIC認証、OpenID認証など)、認可 (権限によるアクセス許可、OAuth 2.0など)、その他多数のセキュリティ対策を可能にするフレームワークです。引用:Spring Security の仕組みを整理してみた
■ CSRFトークン:
フォームを実装しているページに、攻撃者が推測できない値(以下、CSRFトークンと呼びます)※3を埋め込む対策方法です。
Webサーバで生成したCSRFトークンをWebサイト利用者にあらかじめ渡しておき、重要な処理を実行する際には、セッション管理用のCookieと併せてCSRFトークンを送信します。Webサーバは、受信したリクエストに含まれるCSRFトークンがWebサーバで生成したものと一致することを確認します。
引用:クロスサイトリクエストフォージェリ【Cross-Site Request Forgery:CSRF】とは
■ BCrypt:
値のハッシュ化のために設計された暗号関数でソルトと呼ばれるランダムな値をハッシュする値に追加することで、同じパスワードでも異なるハッシュ値が生成されます。
引用:Bcryptのハッシュのアルゴリズムと照合の流れ
環境
Windows 11
IntelliJ IDEA 2025.2 無料版
Java 21
Spring Boot 3.3.4
PostgreSQL 16.10
bootstrap 5.3.3
Thymeleaf
サンプルコード
認証機能付きのログイン画面は以下のように実装します。
1. 認証機能 設定クラス
1-1. パスワードエンコーダーのBean化
1-2. セキュリティフィルタの設定
2. 認証機能 Serviceクラス
2-1. Repositoryの依存性注入
2-2. ログイン時の認証メソッド
3. 画面遷移を行う Controllerクラス
3-1. 画面遷移メソッド
4. ユーザー情報用 Entityクラス
5. ユーザー情報用 Repositoryクラス
5-1. ユーザー名に一致するユーザー情報を返すクエリメソッド
6. ログイン画面
7. ホーム画面
8. POST専用のサンプルAPI
設定クラスの実装例:
package com.example.demo.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
// 1. 認証機能用 設定クラス
@Configuration
public class SecurityConfig {
// 1-1. パスワードエンコーダーのBean化
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
// 1-2. セキュリティフィルタの設定
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(
auth -> auth.requestMatchers(
"/login",
"/error",
"/css/**",
"/js/**")
.permitAll()
.anyRequest().authenticated()
)
.formLogin(
form -> form
.loginPage("/login")
.loginProcessingUrl("/login")
.defaultSuccessUrl("/home", true)
.failureUrl("/login?error")
.permitAll()
)
.logout(logout -> logout
.logoutUrl("/logout")
.logoutSuccessUrl("/login?logout")
.permitAll()
);
return http.build();
}
}
Serviceクラスの実装例:
package com.example.demo.service;
import com.example.demo.domain.AppUser;
import com.example.demo.repository.AppUserRepository;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import java.util.List;
// 2. 認証機能 Serviceクラス
@Service
public class AppUserDetailsService implements UserDetailsService {
// 2-1. Repositoryの依存性注入
private final AppUserRepository userRepo;
public AppUserDetailsService(AppUserRepository userRepo) {
this.userRepo = userRepo;
}
// 2-2. ログイン時の認証メソッド
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
AppUser user = userRepo.findByUsername(username)
.orElseThrow(() -> new UsernameNotFoundException("User not found: " + username));
GrantedAuthority authority = new SimpleGrantedAuthority(user.getRole());
List<GrantedAuthority> authorities = List.of(authority);
return new org.springframework.security.core.userdetails.User(
user.getUsername(),
user.getPassword(),
user.isEnabled(),
true,
true,
true,
authorities
);
}
}
Controllerクラスの実装例:
package com.example.demo.web;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
// 3. 画面遷移を行う Controllerクラス
@Controller
public class LoginController {
// 3-1. 画面遷移メソッド
// ログイン画面
@GetMapping("/login")
public String login() {
return "login";
}
// ログイン後のホーム画面
@GetMapping("/home")
public String home() {
return "index";
}
// トップページ
@GetMapping("/")
public String root() {
return "redirect:/home";
}
}
Entityクラスの実装例:
package com.example.demo.domain;
import jakarta.persistence.*;
// 4. ユーザー情報用 Entityクラス
@Entity
@Table(name = "users") // DB のテーブル名(users テーブルにマッピング)
public class AppUser {
// 主キー
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
// ユーザー名
@Column(nullable = false, unique = true, length = 50)
private String username;
// パスワード
@Column(nullable = false, length = 200)
private String password;
// 権限
@Column(nullable = false, length = 50)
private String role;
// 有効フラグ
@Column(nullable = false)
private boolean enabled = true;
// -----------------------------------------------------
// getter / setter
// -----------------------------------------------------
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getPassword() { return password; }
public void setPassword(String password) { this.password = password; }
public String getRole() { return role; }
public void setRole(String role) { this.role = role; }
public boolean isEnabled() { return enabled; }
public void setEnabled(boolean enabled) { this.enabled = enabled; }
}
Repositoryクラスの実装例:
package com.example.demo.repository;
import com.example.demo.domain.AppUser;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.Optional;
// 5. ユーザー情報用 Repositoryクラス
public interface AppUserRepository extends JpaRepository<AppUser, Long> {
// 5-1. ユーザー名に一致するユーザー情報を返すクエリメソッド
Optional<AppUser> findByUsername(String username);
}
1. 認証機能 設定クラス
// Spring Security の設定クラス
@Configuration
public class SecurityConfig
■@Configuration:
@Beanを定義するための設定クラスであることを明示します。
Beanとは:
Spring が管理するインスタンス(シングルトン)
DI(依存性注入)で他のクラスに渡すことができる。
1-1. パスワードエンコーダーのBean化
// パスワードエンコーダー(BCrypt)を Bean 化する。
// 認証時も Spring Security が自動で BCrypt で照合する。
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
■@Bean + PasswordEncoder:
PasswordEncoderをBean化しています。
Spring Boot + Spring Security の仕組みでは、PasswordEncoder の Bean が 1 つでも定義されていれば、パスワード比較に自動で使用します。これによって、DBに登録されたハッシュ化されたパスワードと、入力されたハッシュ化前のパスワードを自動的に比較することができます。
■BCryptPasswordEncoder:
Spring Security における標準的なパスワードエンコーダ(BCrypt)。
1-2. セキュリティフィルタの設定
// ---------------------------------------------------------
// SecurityFilterChain:
// Spring Security の「セキュリティフィルタの設定」を行うメソッド。
//
// HttpSecurity によって、
// ・どのURLにログインが必要か
// ・ログインフォームのURL
// ・ログアウト設定
// ・CSRF などの安全設定
// を記述していく。
//
// ---------------------------------------------------------
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
// ---------------------------------------------------------
// URL へのアクセス制御(認可)
// ---------------------------------------------------------
http.authorizeHttpRequests(auth -> auth
// ログイン画面(/login)、エラーページ、静的ファイル(css/js)は
// ログインしていなくてもアクセス可能
.requestMatchers("/login", "/error", "/css/**", "/js/**").permitAll()
// 上記以外の全ての URL はログイン必須
.anyRequest().authenticated()
)
// ---------------------------------------------------------
// フォームログイン設定
// ---------------------------------------------------------
.formLogin(form -> form
// 自作ログインページの URL
.loginPage("/login")
// ログインフォームの POST 送信先
// ここに username/password を送ると Spring Security が認証処理する
.loginProcessingUrl("/login")
// 認証成功時に必ず /home へリダイレクト
// 第2引数 true は「必ずここへ遷移(直前のURLを無視)」の意味
.defaultSuccessUrl("/home", true)
// 認証失敗時は /login?error にリダイレクト
.failureUrl("/login?error")
.permitAll() // このログイン処理自体は誰でもアクセスできる
)
// ---------------------------------------------------------
// ログアウト設定
// ---------------------------------------------------------
.logout(logout -> logout
// ログアウト用のURL(POST /logout)
.logoutUrl("/logout")
// ログアウト成功後の遷移先
.logoutSuccessUrl("/login?logout")
.permitAll() // ログアウト処理も誰でもアクセス可(ログイン中ユーザーが使う)
);
// 最終的に SecurityFilterChain を生成して返す
return http.build();
}
■ SecurityFilterChain:
Spring Boot には、SecurityAutoConfiguration という自動設定クラスがあります。起動時に、@Configurationの@Bean SecurityFilterChain を探し、 Web アプリ全体にフィルタを設定します。これらのフィルタが Controller の前に動作するため、ログインや CSRF のチェックが自動的に行われます。
2. 認証機能 Serviceクラス
@Service
public class AppUserDetailsService implements UserDetailsServic
■ UserDetailsService:
Spring Security で ログインユーザーを取得するためのインターフェイス。
username から ユーザーを取得し認証処理に必要な UserDetails を返します。
2-1. Repositoryの依存性注入
private final AppUserRepository userRepo;
public AppUserDetailsService(AppUserRepository userRepo) {
this.userRepo = userRepo;
}
AppUserDetailsService が AppUserRepository を利用できるようにする。
2-2. ログイン時の認証メソッド
// UserDetailsServicのUserDetails(認証メソッド)をオーバーライド
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// ---------------------------------------------------------
// username をもとに、DB(users テーブル) からユーザーを検索する
// AppUserRepository の findByUsername() を利用。
// 見つからなければ UsernameNotFoundException を投げて認証失敗。
// ---------------------------------------------------------
AppUser user = userRepo.findByUsername(username)
.orElseThrow(() -> new UsernameNotFoundException("User not found: " + username));
// ---------------------------------------------------------
// 権限情報(ロール)を Spring Security 用に変換する
// DBの role カラム(例:'ROLE_USER')を
// Spring Security 標準の GrantedAuthority に変換。
// ---------------------------------------------------------
GrantedAuthority authority = new SimpleGrantedAuthority(user.getRole());
List<GrantedAuthority> authorities = List.of(authority);
// ---------------------------------------------------------
// Spring Securityが認証処理に使用できる形式(UserDetails)に変換して返す
//
// org.springframework.security.core.userdetails.User は
// UserDetails インターフェイスの標準実装。
//
// user.getPassword() はすでに BCrypt のハッシュ値が保存されている前提。
// ここで raw password との比較は行わず、ユーザー情報を返すだけ。
//
// 認証フィルタ(UsernamePasswordAuthenticationFilter)が
// PasswordEncoder.matches(raw, encoded) を呼んで比較する。
// ---------------------------------------------------------
return new org.springframework.security.core.userdetails.User(
user.getUsername(), // ユーザー名
user.getPassword(), // ハッシュ化パスワード(BCrypt)
user.isEnabled(), // true のときのみログイン可能
// 以下の3つはアカウント状態チェック
true, // accountNonExpired(アカウント期限切れでない)
true, // credentialsNonExpired(パスワード期限切れでない)
true, // accountNonLocked(アカウントがロックされていない)
authorities // 権限(ROLE_USER など)
);
}
UserDetailsService の抽象メソッドを実装する。
Spring Security のログイン処理の中で自動的に呼び出されるため、自分で呼び出す必要はない。すべて Spring Security が自動的に行う。
■ 引数:
username(ログインフォームで入力されたログインID)
■ 戻り値:
UserDetails(Spring Security が認証に使えるユーザー情報)
3. 画面遷移を行う Controllerクラス
@Controller
public class LoginController
Spring Security に関しての変更は特になし。
通常のControllerクラスを作成する。
3-1. 画面遷移メソッド
// ------------------------------
// ログイン画面の表示
// ------------------------------
// HTTP GET /login に対して処理を行う
@GetMapping("/login")
public String login() {
// → src/main/resources/templates/login.html を表示する
return "login";
}
// ------------------------------
// ログイン後のホーム画面(Book Manager 画面)
// ------------------------------
// HTTP GET /home でホーム画面を表示
@GetMapping("/home")
public String home() {
// → src/main/resources/templates/index.html を表示する
return "index";
}
// ------------------------------
// トップページ(/)にアクセスされた場合の処理
// ------------------------------
// HTTP GET / にアクセスされた時の処理
@GetMapping("/")
public String root() {
// ユーザーが / にアクセスすると
// 自動的に /home へ移動する。
return "redirect:/home";
}
■ ログイン画面:
/loginにアクセス時、ログイン画面を表示する。
■ ホーム画面:
/homeにアクセス時、ログイン画面を表示する。
■ トップページ
/ にはページを置かず、/home にリダイレクトさせる。
"redirect:/home" を返すと、ブラウザに対して
「/home に 302 リダイレクトしなさい」という指示を返す。
4. ユーザー情報用 Entityクラス
package com.example.demo.domain;
import jakarta.persistence.*;
// -----------------------------------------------------
// AppUser エンティティ
// Spring Security のログイン情報として利用される
// -----------------------------------------------------
@Entity
@Table(name = "users") // DB の users テーブルに対応する
public class AppUser {
// -----------------------------------------------------
// 主キー(ID)
// @GeneratedValue:自動採番
// strategy = IDENTITY:PostgreSQL の SERIAL / IDENTITY列を使う
// -----------------------------------------------------
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
// -----------------------------------------------------
// ユーザー名
// Spring Security の認証に必須のフィールド
// -----------------------------------------------------
@Column(nullable = false, unique = true, length = 50)
private String username;
// -----------------------------------------------------
// パスワード(ハッシュ化済み)
// 例:$2a$10$Pq8Q3HUwhXwoUS7yAvVxWu...
// -----------------------------------------------------
@Column(nullable = false, length = 200)
private String password;
// -----------------------------------------------------
// ロール(権限)
// この値がコントローラやセキュリティ設定のアクセス制御で使われる
// 例:ROLE_USER / ROLE_ADMIN
// -----------------------------------------------------
@Column(nullable = false, length = 50)
private String role;
// -----------------------------------------------------
// enabled
// true の場合のみログインを許可する
// -----------------------------------------------------
@Column(nullable = false)
private boolean enabled = true;
// -----------------------------------------------------
// getter / setter
// -----------------------------------------------------
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getPassword() { return password; }
public void setPassword(String password) { this.password = password; }
public String getRole() { return role; }
public void setRole(String role) { this.role = role; }
public boolean isEnabled() { return enabled; }
public void setEnabled(boolean enabled) { this.enabled = enabled; }
}
5. ユーザー情報用 Repositoryクラス
public interface AppUserRepository extends JpaRepository<AppUser, Long>
ユーザー情報を取得する実際のDB操作(SQL)を行う。
5-1. ユーザー名に一致するユーザー情報を返すクエリメソッド
Optional<AppUser> findByUsername(String username);
SELECT * FROM users WHERE username = ?
というSQLが自動で実行されるクエリメソッド。
Spring Security がログイン時のパスワード検証を行うために呼び出す。
6. ログイン画面
<!doctype html>
<html xmlns:th="http://www.thymeleaf.org" lang="ja">
<head>
<meta charset="UTF-8">
<title>ログイン</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css"
rel="stylesheet">
</head>
<body class="bg-light">
<div class="container mt-5">
<div class="row justify-content-center">
<div class="col-md-4">
<h1 class="h4 mb-3 text-center">ログイン</h1>
<!-- -----------------------------
ログイン失敗時のエラーメッセージ
Spring Security は ?error を自動付与
----------------------------- -->
<div th:if="${param.error}" class="alert alert-danger">
ユーザー名またはパスワードが正しくありません。
</div>
<!-- -----------------------------
ログアウト完了時のメッセージ
?logout 付きで遷移した場合に表示
----------------------------- -->
<div th:if="${param.logout}" class="alert alert-info">
ログアウトしました。
</div>
<!-- -----------------------------
ログインフォーム
POST /login に送信する
(SecurityConfig で loginProcessingUrl("/login") を設定)
----------------------------- -->
<form method="post" th:action="@{/login}">
<!-- ユーザー名入力欄 -->
<div class="mb-3">
<label for="username" class="form-label">ユーザー名</label>
<!-- name="username"(Spring Security のデフォルト名称) -->
<input type="text" class="form-control" id="username"
name="username"
autocomplete="username" required>
</div>
<!-- パスワード入力欄 -->
<div class="mb-3">
<label for="password" class="form-label">パスワード</label>
<!-- name="password" (Spring Security のデフォルト名称) -->
<input type="password" class="form-control" id="password"
name="password"
autocomplete="current-password" required>
</div>
<!-- ----------------------------------------------
CSRFトークンをログイン後の画面に埋め込む
Spring Security がリクエストごとに _csrf を自動提供
th:name : _csrf.parameterName 例: "_csrf"
th:value : _csrf.token 例: "f342a98c-...-..."
hidden なのでユーザーには見えないが、POST 送信時に必須
---------------------------------------------- -->
<input type="hidden"
th:name="${_csrf.parameterName}"
th:value="${_csrf.token}"/>
<!-- 送信ボタン -->
<button type="submit" class="btn btn-primary w-100">ログイン</button>
</form>
</div>
</div>
</div>
</body>
</html>
7. ホーム画面
<!doctype html>
<html xmlns:th="http://www.thymeleaf.org" lang="ja">
<head>
<meta charset="UTF-8">
<title>ホーム</title>
<!--
JavaScript(fetch) でトークンを取得するために、CSRFトークンを埋め込む
Spring Security の CSRF 保護を利用する場合、
ログイン後の画面には「CSRFトークン」が自動的に付与される。
th:content="${_csrf.token}" : トークンの値を meta に埋め込む
th:content="${_csrf.headerName}" : サーバーが期待するヘッダー名(例: X-CSRF-TOKEN)
-->
<meta name="_csrf" th:content="${_csrf.token}"/>
<meta name="_csrf_header" th:content="${_csrf.headerName}"/>
</head>
<body>
<h1>ログイン済みページ</h1>
<p>ようこそ!</p>
<!-- ----------------------------------------------------------
ログアウトフォーム
/logout は POST メソッドでないと受け付けないため、
CSRFトークンを hidden フィールドで送信する必要がある。
----------------------------------------------------------- -->
<form th:action="@{/logout}" method="post">
<button type="submit">ログアウト</button>
<!--
hidden項目に CSRF トークンを埋め込む。
th:name="${_csrf.parameterName}" : "_csrf"
th:value="${_csrf.token}" : セッションに保持されているトークン
-->
<input type="hidden"
th:name="${_csrf.parameterName}"
th:value="${_csrf.token}"/>
</form>
<hr>
<h3>CSRF付きのPOSTリクエストを送るボタン</h3>
<button id="sendBtn">POST送信</button>
<!-- ----------------------------------------------------------
JavaScript(サンプルコードでは直接記述)
----------------------------------------------------------- -->
<script>
// DOM が読み込まれてから実行
document.addEventListener('DOMContentLoaded', () => {
// ---------------------------------------------------------
// metaタグから CSRFトークンとヘッダー名を取得
//
// csrfToken :Spring Security が発行するトークン
// csrfHeader :サーバーが受け付けるヘッダー名(例: "X-CSRF-TOKEN")
//
// fetch() の際に、このヘッダー名+トークンを送る必要がある。
// ---------------------------------------------------------
const csrfToken = document.querySelector('meta[name="_csrf"]').content;
const csrfHeader = document.querySelector('meta[name="_csrf_header"]').content;
// ---------------------------------------------------------
// POSTリクエストを送信するボタンイベント
// ---------------------------------------------------------
document.getElementById("sendBtn").addEventListener("click", async () => {
/*
fetch("/api/sample-post") の POST では、
CSRF をヘッダーに付けないと 403 Forbidden になる。
headers: {
[csrfHeader]: csrfToken
}
Spring Security の CsrfFilter が内部で
「セッションのトークンと一致しているか」を検証する。
*/
const response = await fetch("/api/sample-post", {
method: "POST",
headers: {
"Content-Type": "application/json",
// CSRF トークンを送信(自動的に検証される)
[csrfHeader]: csrfToken
},
// サンプルとして送る JSON データ
body: JSON.stringify({ message: "CSRF付きPOST" })
});
// -----------------------------------------------------
// 結果表示
// -----------------------------------------------------
if (response.ok) {
alert("POST成功");
} else {
alert("POST失敗: " + response.status);
}
});
});
</script>
</body>
</html>
8. POST専用のサンプルAPI
REST コントローラの実装例:
package com.example.demo.web;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api")
public class SampleApiController {
// ----------------------------------------------
// POST /api/sample-post
// → CSRFトークンを付与して fetch で呼び出す API
// ----------------------------------------------
@PostMapping("/sample-post")
public ResponseEntity<?> samplePost(@RequestBody SampleRequest req) {
// 入力されたデータをログに出す(動作確認用)
System.out.println("受信メッセージ: " + req.getMessage());
// クライアントに返すレスポンスの例
return ResponseEntity.ok(
new SampleResponse("サーバーで受け取りました", req.getMessage())
);
}
}
リクエストDTOの実装例:
package com.example.demo.web.dto;
public class SampleRequest {
private String message;
public String getMessage() { return message; }
public void setMessage(String message) { this.message = message; }
}
レスポンスDTOの実装例:
package com.example.demo.web.dto;
public class SampleResponse {
private String status;
private String received;
public SampleResponse(String status, String received) {
this.status = status;
this.received = received;
}
public String getStatus() { return status; }
public String getReceived() { return received; }
}
補足:初期ユーザーの設定
サンプルコードでは、初期ユーザーの設定を手動で行います。
■ 1. ログインで使用するパスワードをハッシュ化:
package com.example.demo;
// Spring Security が提供する BCrypt アルゴリズムのパスワードハッシュ化クラスを読み込む
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
public class PasswordGen {
public static void main(String[] args) {
// ハッシュ化クラスのインスタンスを作成
var encoder = new BCryptPasswordEncoder();
// ハッシュ化した結果をコンソールに出力
System.out.println(encoder.encode("password")); // "password" は任意のパスワードに変更
}
}
BCryptPasswordEncoder のインスタンスを作成し、encode(...)でパスワードを BCrypt でハッシュ化しています。
コンソールの出力結果をユーザーのパスワードとしてDBに保存します。
出力例:$2a$10$p.y.tUK5TSEG8qI10QzfsuvJLlMV4cAocdBudnfQwtdkUEowTG2ui
登録画面を作成する場合、同じくハッシュ化してDBに保存します。
■ 2. PostgreSQL内で直接 INSERTのSQL文 を実行:
INSERT INTO users (username, password, role, enabled)
VALUES ('user',
'例:$2a$10$p.y.tUK5TSEG8qI10QzfsuvJLlMV4cAocdBudnfQwtdkUEowTG2ui',
'ROLE_USER',
true);
ハッシュ化済みのパスワードを使用して、ユーザーを登録します。
ログイン時は、ハッシュ化していない元のパスワードを使用します。
補足:依存関係(build.gradle)
plugins {
id 'java'
id 'org.springframework.boot' version '3.3.4'
id 'io.spring.dependency-management' version '1.1.6'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
java { toolchain { languageVersion = JavaLanguageVersion.of(21) } }
repositories { mavenCentral() }
dependencies {
// SpringBoot
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-security'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
// DB
runtimeOnly 'com.h2database:h2'
runtimeOnly 'org.postgresql:postgresql:42.7.4'
}
test { useJUnitPlatform() }