メモ > 技術 > フレームワーク: SpringBoot > 認証
認証
Spring Boot Starter Securityを導入することで対応できる
pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
src/main/java/com/example/demo/config/SecurityConfig.java
package com.example.demo.config;
import org.springframework.boot.autoconfigure.security.servlet.PathRequest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
//http.authorizeRequests().anyRequest().permitAll();
http
.formLogin((form) -> form
// 認証を行うURL
.loginProcessingUrl("/admin/")
// ログインページのURL
.loginPage("/admin/")
// ログインユーザ名の項目
.usernameParameter("username")
// ログインパスワードの項目
.passwordParameter("password")
// 認証に成功したときにリダイレクトするURL
.defaultSuccessUrl("/admin/home")
// 認証に失敗したときにリダイレクトするURL
.failureUrl("/admin/?error")
// すべてのユーザがアクセス可能
.permitAll()
)
.logout((logout) -> logout
// ログアウトページのURL
.logoutUrl("/admin/logout")
// ログアウトしたときにリダイレクトするURL
.logoutSuccessUrl("/admin/")
)
.authorizeHttpRequests((requests) -> requests
// CSSなどはログイン無しでもアクセス可能
.requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
// ログイン無しでもアクセス可能なURL
.requestMatchers("/", "/now", "/task/**", "/dev/**").permitAll()
// 「/admin/」へのアクセスには「ADMIN」権限が必要
.requestMatchers("/admin/**").hasRole("ADMIN")
// 他のページはすべて認証が必要
.anyRequest().authenticated()
);
return http.build();
}
@Bean
public UserDetailsService userDetailsService() {
User.UserBuilder users = User.withDefaultPasswordEncoder();
// 認証情報1
UserDetails admin = users
.username("admin")
.password("abcd1234")
.roles("ADMIN")
.build();
// 認証情報2
UserDetails guest = users
.username("guest")
.password("abcd1234")
.roles("ADMIN")
.build();
return new InMemoryUserDetailsManager(admin, guest);
}
}
src/main/java/com/example/demo/controller/AdminController.java
package com.example.demo.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class AdminController {
@GetMapping(value = "/admin/")
String index() {
return "admin/index";
}
@GetMapping(value = "/admin/home")
String home() {
return "admin/home";
}
}
templates/layout/backend.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
<head>
<meta charset="UTF-8">
<title>Admin</title>
</head>
<body>
<header th:fragment="header">
<h1>Demo</h1>
</header>
<th:block layout:fragment="content"></th:block>
<footer th:fragment="footer">
<p><small>This is demo site.</small></p>
</footer>
</body>
</html>
src/main/resources/templates/admin/index.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{layout/backend}">
<head>
<title>ログイン | Admin</title>
</head>
<body>
<th:block layout:fragment="content">
<main>
<p>ログインページ。</p>
<p th:if="${param.error}">ユーザ名またはパスワードが異なります。</p>
<p th:if="${param.logout}">ログアウトしました。</p>
<form th:action="@{/admin/}" method="post">
<dl>
<dt>ユーザ名</dt>
<dd><input type="text" name="username" value=""></dd>
<dt>テキスト</dt>
<dd><input type="password" name="password" value=""></dd>
</dl>
<p><input type="submit" value="ログイン"></p>
</form>
</main>
</th:block>
</body>
</html>
src/main/resources/templates/admin/home.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{layout/backend}">
<head>
<title>ホーム | Admin</title>
</head>
<body>
<th:block layout:fragment="content">
<main>
<p>管理画面にログインしています。</p>
<form th:action="@{/admin/logout}" method="post">
<p><input type="submit" value="ログアウト"></p>
</form>
</main>
</th:block>
</body>
</html>
これで
http://localhost:8080/ は通常どおりアクセスでき、
http://localhost:8080/admin/ から先に進もうとすると認証を求められる
認証を求めるページや認証情報は、SecurityConfig.java で指定している
「/admin/**」のようなURL指定については以下を参照
アスタリスク1つだと同階層のみ対象だが、アスタリスク2つだと指定階層以下が対象となる
antMatchersのワイルドカードについて - てのひら
https://www.tenohira.xyz/tech/spring-antmatchers-wildcard/
アクセスできるURLは以下のようにしている
「原則ログインが必要なシステム。ログイン画面など一部ページのみ誰でもアクセスできる」という場合はこれで良さそうだが、
.authorizeHttpRequests((requests) -> requests
// CSSなどはログイン無しでもアクセス可能
.requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
// ログイン無しでもアクセス可能なURL
.requestMatchers("/", "/now", "/task/**", "/dev/**").permitAll()
// 「/admin/」へのアクセスには「ADMIN」権限が必要
.requestMatchers("/admin/**").hasRole("ADMIN")
// 他のページはすべて認証が必要
.anyRequest().authenticated()
);
「/admin/ は管理者用ページ。他は誰でもアクセスできるページ」という場合、以下くらいの指定でもいいかもしれない
.authorizeHttpRequests((requests) -> requests
// 「/admin/」へのアクセスには「ADMIN」権限が必要
.requestMatchers("/admin/**").hasRole("ADMIN")
// 他のページはすべてアクセス可能
.anyRequest().permitAll()
);
ログイン、ログアウトの実装|Javaの基礎を学び終えたアナタに贈る, SpringBoot/SpringSecurityによる掲示板開発ハンズオン
https://zenn.dev/angelica/books/52be1e365c61ea/viewer/1c1ebe
Spring Boot ログイン画面 - 公式サンプルコード
https://spring.pleiades.io/guides/gs/securing-web/
Spring Boot でSpring Securityを使ってみる(SecurityFilterChain) - Qiita
https://qiita.com/TaikiTkwkbysh/items/9e2a7dfdf9f0bed9e779
インメモリ認証 :: Spring Security - リファレンス
https://spring.pleiades.io/spring-security/reference/servlet/authentication/passwords/in-memory.html
Spring Boot にて Spring Security を使用した直後の認証の仕組みをソースコードとともに確認する
https://zenn.dev/kiyotatakeshi/articles/fc593c768ad7e0
SpringSecurityの導入/CSRF対策|Javaの基礎を学び終えたアナタに贈る, SpringBoot/SpringSecurityによる掲示板開発ハンズオン
https://zenn.dev/angelica/books/52be1e365c61ea/viewer/f0683a
timestamp status 999 error none message no message available - Qiita
https://qiita.com/TBATYOF/items/4e87a6297cc78f43e842
WebSecurityConfigurerAdapter を継承するのは古い方法で、SecurityFilterChain を定義するのが新しい方法らしい
WebSecurityConfigurerAdapterが非推奨になってた
https://volkruss.com/posts/p2691/
Spring Security 5.4〜6.0でセキュリティ設定の書き方が大幅に変わる件 - Qiita
https://qiita.com/suke_masa/items/908805dd45df08ba28d8
最新の6.0で学ぶ!初めてのひとのためのSpring Security | ドクセル
https://www.docswell.com/s/MasatoshiTada/KGVY9K-spring-security-intro
以下は古い書き方だが参考までに
Spring Securityの認証のサンプル(SpringBoot) | ITSakura
https://itsakura.com/spring-security-boot
【SpringBoot入門】Spring Securityで認証機能 - Qiita
https://qiita.com/morioheisei/items/ecfeee4860944d0b4a3b
Spring Boot入門:Spring Securityで認証と認可 | ツチヤの備忘録
https://www.tsuchiya.blog/spring-boot-step7/