概要
VS CodeSpringBootアプリケーションを作成し簡易なSpringSecurityを実装する。
また、インメモリにユーザ情報を持たせアクセス制御も行う
参考記事
Spring Security 6.0 入門
初めての人のためのSpring Security
目次
環境情報
項目 | バージョン |
---|---|
Java | 17 |
SpringBoot | 3.2.4 |
SpringSecurity | 6 |
SpringBootアプリケーションの作成
VS Codeで以下の依存関係を追加したSpringBootアプリケーションを作成する
dependencies | 備考 |
---|---|
Spring Web | 自己完結型の HTTP サーバーを作成できる |
Thymeleaf | Javaのウェブ開発用テンプレートエンジン |
SpringSecurity | Spring Securityを用いた認証・認可に利用 |
参考: VS CodeでSpring Bootアプリケーション作成 とDB連携
View作成
権限によるアクセス制御を実装するため、
「index.html」, 「user.html」, 「admin.html」の3つのページを用意する。
<!DOCTYPE html>
<html lang="ja" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ホーム</title>
</head>
<body>
<h1>index.html</h1>
<a href="./user.html" th:href="@{/user}">ユーザページ</a>
</body>
</html>
<!DOCTYPE html>
<html lang="ja" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ユーザーページ</title>
</head>
<body>
<h1>user.html</h1>
<a href="./admin.html"th:href="@{/admin}">管理者ページ</a><br>
<a href="./logout.html" th:href="@{/logout}">ログアウト</a>
</form>
</body>
</html>
<!DOCTYPE html>
<html lang="ja" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>管理者ページ</title>
</head>
<body>
<h1>admin.html</h1>
<a href="./user.html" th:href="@{/}">ユーザーページ</a><br>
<a href="./logout.html" th:href="@{/logout}">ログアウト</a>
</body>
</html>
Controller作成
「LoginController.java」を作成する
package com.example.demo.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("")
public class LoginController {
@GetMapping("/user")
public String user(){
return "/user";
}
@GetMapping("/admin")
public String admin(){
return "/admin";
}
}
アプリケーションを起動し、「http://localhost:8080/」 に接続するとSpring Securityによりログイン画面が表示される
(SpringSecurityにはデフォルトで「/login」と「/logout」が用意されている
現時点では、SpringSecurityの設定を行なっていないため、全てのページに対してSecurityがかかっている状態)
Username: user
Password: 起動時のコンソールに出力される(実行ごとに異なる)
「Sign in」するとユーザーページ(index.html)に遷移する
サインイン後は、全てのページへのアクセスが可能となる
SpringSecurityの設定
「SecurityConfig.java」を作成し、ユーザー情報と各ページの参照権限を設定する
アクセス制御設定
ユーザー/ページ | 未ログイン | user1 | admin |
---|---|---|---|
index.html | ⚪️ | ⚪️ | ⚪️ |
user.html | ❌ | ⚪️ | ⚪️ |
admin.html | ❌ | ❌ | ⚪️ |
package com.example.demo.common;
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.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
// パスワードの暗号化
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
InMemoryUserDetailsManager userDetailsService() {
// 管理者設定
UserDetails admin = User
.withUsername("admin")
.password(passwordEncoder().encode("admin"))
.roles("ADMIN")
.build();
// ユーザー設定
UserDetails user = User
.withUsername("user")
.password(passwordEncoder().encode("user"))
.roles("USER")
.build();
return new InMemoryUserDetailsManager(admin, user);
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
// ログインページの許可設定
.formLogin(login -> login // フォーム認証を使う
.defaultSuccessUrl("/user") // 認証成功時のデフォルトの遷移先
.permitAll())
// リクエストの許可設定
.authorizeHttpRequests(authz -> authz
// index.html の参照権限
.requestMatchers("/")
.permitAll()
// user.html の参照権限
.requestMatchers("/user")
.hasAnyRole("USER","ADMIN")
// admin.html の参照権限
.requestMatchers("/admin")
.hasRole("ADMIN"));
return http.build();
}
}
アプリケーションを再起動し、以下内容が実装できたことを確認する
- http://localhost:8080/ に接続
- 表示されたindex.html で「ユーザーページ」を押下
- ログイン画面が表示される
- 「user」, 「admin」でログインし、アクセス制御が正しく行われていることを確認する
参考資料
SpringSecurityのアーキテクチャー
インメモリ認証(InMemoryUserDetailsManager)
User(org.springframework.security.core.userdetails.User)
付録
ログインしているユーザーの権限によって、Viewで表示させるコンテンツを変更する
htmlタグに以下の記載を追加
xmlns:sec="http://www.thymeleaf.org/extras/spring-security"
管理者ページへのリンクに以下の記載を追加
sec:authorize="hasAuthority('ROLE_ADMIN')"
上記の記載により、ADMIN権限でログインした場合のみリンクが表示されるようになる
<!DOCTYPE html>
<!-- 修正 -->
<html lang="ja" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ユーザーページ</title>
</head>
<body>
<h1>user.html</h1>
<!-- 修正 -->
<a sec:authorize="hasAuthority('ROLE_ADMIN')" href="./admin.html" th:href="@{/admin}">管理者ページ</a><br>
<a href="./logout.html" th:href="@{/logout}">ログアウト</a>
</body>
</html>