このガイドでは、Spring Securityで保護されているリソースを使用して単純なWebアプリケーションを作成するプロセスを順を追って説明します。

構築するもの

ユーザーの固定リストによるログインフォームでページを保護するSpring MVCアプリケーションを構築します。

必要なもの

このガイドを完了する方法

ほとんどのSpring 入門ガイドと同様に、最初から始めて各ステップを完了するか、すでに慣れている場合は基本的なセットアップステップをバイパスできます。いずれにしても、最終的に動作するコードになります。

最初から始めるには、Spring Initializrから開始に進みます。

基本スキップするには、次の手順を実行します。

完了したときは、gs-securing-web/completeのコードに対して結果を確認できます。

Spring Initializrから開始

すべてのSpringアプリケーションの場合、Spring Initializr(英語) から開始する必要があります。Initializrは、アプリケーションに必要なすべての依存関係をすばやく取り込む方法を提供し、多くのセットアップを行います。この例では、Spring、Web、およびThymeleafの依存関係が必要です。次のイメージは、このサンプルプロジェクト用に設定されたInitializrを示しています。

initializr
前の図は、Mavenがビルドツールとして選択されたInitializrを示しています。Gradleも使用できます。また、com.example および securing-web の値をそれぞれグループおよびアーティファクトとして表示します。このサンプルの残りの部分では、これらの値を使用します。

次のリストは、Mavenを選択したときに作成される pom.xml ファイルを示しています。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.2.2.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>securing-web</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>securing-web</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
			<exclusions>
				<exclusion>
					<groupId>org.junit.vintage</groupId>
					<artifactId>junit-vintage-engine</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

次のリストは、Gradleを選択したときに作成される build.gradle ファイルを示しています。

plugins {
	id 'org.springframework.boot' version '2.2.2.RELEASE'
	id 'io.spring.dependency-management' version '1.0.8.RELEASE'
	id 'java'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'

repositories {
	mavenCentral()
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
	implementation 'org.springframework.boot:spring-boot-starter-web'
	testImplementation('org.springframework.boot:spring-boot-starter-test') {
		exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
	}
}

test {
	useJUnitPlatform()
}

保護されていないWebアプリケーションを作成する

Webアプリケーションにセキュリティを適用する前に、保護するWebアプリケーションが必要です。このセクションでは、簡単なWebアプリケーションを作成する方法を説明します。次に、次のセクションでSpring Securityで保護します。

Webアプリケーションには、ホームページと「Hello, World」ページの2つの単純なビューが含まれています。ホームページは、次のThymeleafテンプレート( src/main/resources/templates/home.htmlから)で定義されています。

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org" xmlns:sec="https://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
    <head>
        <title>Spring Security Example</title>
    </head>
    <body>
        <h1>Welcome!</h1>

        <p>Click <a th:href="@{/hello}">here</a> to see a greeting.</p>
    </body>
</html>

この単純なビューには、/hello ページへのリンクが含まれています。このページは、次のThymeleafテンプレートで定義されています( src/main/resources/templates/hello.htmlから)。

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org"
      xmlns:sec="https://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
    <head>
        <title>Hello World!</title>
    </head>
    <body>
        <h1>Hello world!</h1>
    </body>
</html>

WebアプリケーションはSpring MVCに基づいています。そのため、Spring MVCを構成し、View Controllerをセットアップしてこれらのテンプレートを公開する必要があります。次のリスト( src/main/java/com/example/securingweb/MvcConfig.javaから)は、アプリケーションでSpring MVCを構成するクラスを示しています。

package com.example.securingweb;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class MvcConfig implements WebMvcConfigurer {

	public void addViewControllers(ViewControllerRegistry registry) {
		registry.addViewController("/home").setViewName("home");
		registry.addViewController("/").setViewName("home");
		registry.addViewController("/hello").setViewName("hello");
		registry.addViewController("/login").setViewName("login");
	}

}

addViewControllers() メソッド( WebMvcConfigurerの同じ名前のメソッドをオーバーライドする)は、4つのView Controllerを追加します。2つのView Controllerは、名前が homehome.htmlで定義)のビューを参照し、別のView Controllerは hellohello.htmlで定義)という名前のビューを参照します。4番目のView Controllerは、loginという名前の別のビューを参照します。次のセクションでそのビューを作成します。

この時点で、「アプリケーションの実行」にジャンプして、何にもログインすることなくアプリケーションを実行できます。

セキュリティで保護されていないWebアプリケーションができたため、セキュリティを追加できます。

Spring Securityをセットアップする

権限のないユーザーが /helloのグリーティングページを表示できないようにしたいとします。現在のように、訪問者がホームページのリンクをクリックすると、彼らを止める障壁のない挨拶が表示されます。訪問者がそのページを見る前にサインインすることを強制するバリアを追加する必要があります。

そのためには、アプリケーションでSpring Securityを構成します。Spring Securityがクラスパスにある場合、Spring Bootは「基本」認証ですべてのHTTPエンドポイントを自動的に保護します。ただし、セキュリティ設定をさらにカスタマイズできます。最初に行う必要があるのは、Spring Securityをクラスパスに追加することです。

Gradleでは、次のリストに示すように、build.gradledependencies クロージャーに2行(アプリケーション用とテスト用)を追加する必要があります。

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

次のリストは、完成した build.gradle ファイルを示しています。

plugins {
	id 'org.springframework.boot' version '2.2.2.RELEASE'
	id 'io.spring.dependency-management' version '1.0.8.RELEASE'
	id 'java'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'

repositories {
	mavenCentral()
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
	implementation 'org.springframework.boot:spring-boot-starter-web'
	implementation 'org.springframework.boot:spring-boot-starter-security'
	implementation 'org.springframework.security:spring-security-test'
	testImplementation('org.springframework.boot:spring-boot-starter-test') {
		exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
	}
}

test {
	useJUnitPlatform()
}

Mavenでは、次のリストに示すように、pom.xml<dependencies> 要素に2つの追加エントリ(アプリケーション用とテスト用)を追加する必要があります。

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

次のリストは、完成した pom.xml ファイルを示しています。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.2.2.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>securing-web</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>securing-web</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-security</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-test</artifactId>
			<scope>test</scope>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
			<exclusions>
				<exclusion>
					<groupId>org.junit.vintage</groupId>
					<artifactId>junit-vintage-engine</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

次のセキュリティ構成( src/main/java/com/example/securingweb/WebSecurityConfig.javaから)により、認証されたユーザーのみがシークレットグリーティングを見ることができます。

package com.example.securingweb;

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.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
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;

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http
			.authorizeRequests()
				.antMatchers("/", "/home").permitAll()
				.anyRequest().authenticated()
				.and()
			.formLogin()
				.loginPage("/login")
				.permitAll()
				.and()
			.logout()
				.permitAll();
	}

	@Bean
	@Override
	public UserDetailsService userDetailsService() {
		UserDetails user =
			 User.withDefaultPasswordEncoder()
				.username("user")
				.password("password")
				.roles("USER")
				.build();

		return new InMemoryUserDetailsManager(user);
	}
}

WebSecurityConfig クラスには @EnableWebSecurity アノテーションが付けられており、Spring SecurityのWebセキュリティサポートを有効にし、Spring MVC統合を提供します。また、WebSecurityConfigurerAdapter を継承し、いくつかのメソッドをオーバーライドして、Webセキュリティ構成のいくつかの詳細を設定します。

configure(HttpSecurity) メソッドは、セキュリティで保護する必要があるURLパスと保護しないURLパスを定義します。具体的には、/ および /home パスは、認証を必要としないように構成されています。他のすべてのパスは認証される必要があります。

ユーザーが正常にログインすると、認証を必要とする以前に要求されたページにリダイレクトされます。カスタム /login ページ( loginPage()で指定されている)があり、誰でもそれを表示できます。

userDetailsService() メソッドは、単一のユーザーでメモリ内ユーザーストアをセットアップします。そのユーザーには、userのユーザー名、passwordのパスワード、および USERのロールが与えられます。

次に、ログインページを作成する必要があります。 login ビュー用のView Controllerがすでに存在するため、次のリスト( src/main/resources/templates/login.htmlから)が示すように、ログインビュー自体を作成するだけで済みます。

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org"
      xmlns:sec="https://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
    <head>
        <title>Spring Security Example </title>
    </head>
    <body>
        <div th:if="${param.error}">
            Invalid username and password.
        </div>
        <div th:if="${param.logout}">
            You have been logged out.
        </div>
        <form th:action="@{/login}" method="post">
            <div><label> User Name : <input type="text" name="username"/> </label></div>
            <div><label> Password: <input type="password" name="password"/> </label></div>
            <div><input type="submit" value="Sign In"/></div>
        </form>
    </body>
</html>

このThymeleafテンプレートは、ユーザー名とパスワードを取得して /loginに投稿するフォームを提示します。構成されているように、Spring Securityはその要求をインターセプトし、ユーザーを認証するフィルターを提供します。ユーザーが認証に失敗すると、ページは /login?errorにリダイレクトされ、ページに適切なエラーメッセージが表示されます。ログアウトに成功すると、アプリケーションが /login?logoutに送信され、ページに適切な成功メッセージが表示されます。

最後に、現在のユーザー名を表示してサインアウトする方法を訪問者に提供する必要があります。これを行うには、次のリスト( src/main/resources/templates/hello.htmlから)が示すように、hello.html を更新して現在のユーザーに挨拶し、Sign Out フォームを含めます。

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org"
      xmlns:sec="https://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
    <head>
        <title>Hello World!</title>
    </head>
    <body>
        <h1 th:inline="text">Hello [[${#httpServletRequest.remoteUser}]]!</h1>
        <form th:action="@{/logout}" method="post">
            <input type="submit" value="Sign Out"/>
        </form>
    </body>
</html>

Spring Securityと HttpServletRequest#getRemoteUser()の統合を使用して、ユーザー名を表示します。「サインアウト」フォームは、POSTを /logoutに送信します。ログアウトに成功すると、ユーザーを /login?logoutにリダイレクトします。

アプリケーションの実行

Spring Initializrは、アプリケーションクラスを作成します。この場合、クラスを変更する必要はありません。次のリスト( src/main/java/com/example/securingweb/SecuringWebApplication.javaから)は、アプリケーションクラスを示しています。

package com.example.securingweb;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SecuringWebApplication {

	public static void main(String[] args) throws Throwable {
		SpringApplication.run(SecuringWebApplication.class, args);
	}

}

実行可能JARを構築する

コマンドラインからGradleまたはMavenを使用してアプリケーションを実行できます。必要なすべての依存関係、クラス、およびリソースを含む単一の実行可能JARファイルを構築して実行することもできます。実行可能なjarを構築すると、開発ライフサイクル全体、さまざまな環境などで、サービスをアプリケーションとして簡単に提供、バージョン管理、およびデプロイできます。

Gradleを使用する場合、./gradlew bootRunを使用してアプリケーションを実行できます。または、次のように、./gradlew build を使用してJARファイルをビルドしてから、JARファイルを実行できます。

java -jar build/libs/gs-securing-web-0.1.0.jar

Mavenを使用する場合、./mvnw spring-boot:runを使用してアプリケーションを実行できます。または、次のように、./mvnw clean package でJARファイルをビルドしてから、JARファイルを実行できます。

java -jar target/gs-securing-web-0.1.0.jar
ここで説明する手順は、実行可能なJARを作成します。クラシックWARファイルを作成することもできます。

アプリケーションが起動したら、ブラウザで http://localhost:8080を指定します。次のイメージが示すように、ホームページが表示されます。

The application’s home page

リンクをクリックすると、/helloのグリーティングページに移動しようとします。ただし、そのページは保護されており、まだログインしていないため、次のイメージに示すように、ログインページに移動します。

The login page
セキュリティで保護されていないバージョンでここにジャンプした場合、ログインページは表示されません。セキュリティベースのコードの残りをバックアップして作成する必要があります。

ログインページで、ユーザー名とパスワードのフィールドにそれぞれ userpassword を入力して、テストユーザーとしてサインインします。ログインフォームを送信すると、認証され、次のイメージに示すようにグリーティングページに移動します。

The secured greeting page

サインアウトボタンをクリックすると、認証が取り消され、ログアウトされたことを示すメッセージとともにログインページに戻ります。

要約

おめでとう! Spring Securityで保護された単純なWebアプリケーションを開発しました。

関連事項

次のガイドも役立ちます。

新しいガイドを作成したり、既存のガイドに貢献したいですか? 投稿ガイドラインを参照してください(GitHub)

すべてのガイドは、コード用のASLv2ライセンス、およびドキュメント用のAttribution、NoDerivativesクリエイティブコモンズライセンス(英語) でリリースされています。