Spring Security フォームログインのサンプルコード
[History] [Last Modified] (2017/07/30 10:14:03)
ここは
趣味のプログラミングを楽しむための情報共有サービス。記事の一部は有料設定にして公開できます。 詳しくはこちらをクリック📝
Recent posts
Popular pages

概要

Spring フレームワークによる Web アプリケーション開発で、ログイン処理を実装する際は Spring Security が便利です。ここでは特に、こちらのページに記載の Spring Boot で Web アプリケーションを開発する場合を対象とし、フォームによる ID/Password ログインを行うためのサンプルコードをまとめます。

公式ドキュメント

フォームログインのサンプル

基本的な Gradle プロジェクトです。ここでは簡単のため、フォームでログインするユーザーは、DB ではなく Java ソースコードにハードコーディングされたものを利用します。

.
|-- build.gradle
|-- gradle
|   `-- wrapper
|       |-- gradle-wrapper.jar
|       `-- gradle-wrapper.properties
|-- gradlew
|-- gradlew.bat
`-- src
    `-- main
        |-- java
        |   `-- hello
        |       |-- Application.java
        |       |-- MvcConfig.java
        |       `-- WebSecurityConfig.java
        `-- resources
            `-- templates
                |-- hello.html
                |-- home.html
                `-- login.html

build.gradle

buildscript {
    ext {
        springBootVersion = '1.5.3.RELEASE'
    }
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
    }
}

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'org.springframework.boot'

jar {
    baseName = 'gs-spring-boot'
    version =  '0.1.0'
}

repositories {
    mavenCentral()
}

sourceCompatibility = 1.8
targetCompatibility = 1.8

dependencies {
    compile('org.springframework.boot:spring-boot-starter-thymeleaf')
    compile('org.springframework.boot:spring-boot-starter-security')
    compile('org.springframework.boot:spring-boot-devtools')
}

Java ソースコード

src/main/java/hello/Application.java

アノテーションの意味についてはこちらをご参照ください。

package hello;

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

@SpringBootApplication
public class Application {

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

src/main/java/hello/MvcConfig.java

今回のサンプルコードでは @Controller コントローラが登場せず、@RequestMapping("/") 設定がなされません。代わりに、以下の Config Java ファイルでパスと View のマッピングを行っています。

package hello;

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

@Configuration
public class MvcConfig extends WebMvcConfigurerAdapter {

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

src/main/java/hello/WebSecurityConfig.java

@EnableWebSecurity アノテーションが設定されて WebSecurityConfigurerAdapter を継承したクラスで Spring Security の既定の挙動をカスタマイズできます。ユーザー名が user でパスワードはアプリケーション起動時にログで確認できる Basic 認証が既定ですが、以下ではログインフォーム認証をユーザ名 user パスワード password で行うように変更しています。

パスに関する設定の意味はそれぞれ以下のとおりです。いずれも公式ドキュメントで更に詳細な設定が可能なことが確認できます。

  • .authorizeRequests() パス //home は認証なしで表示できるように設定しています。
  • .formLogin() 認証用のパスを設定しています。
  • .logout() ログアウト用のエンドポイントが自動生成されるように設定しています。

WebSecurityConfig.java

package hello;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;

@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();
    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth
            .inMemoryAuthentication()
                .withUser("user").password("password").roles("USER"); // sets up an in-memory user store with a single user.
    }
}

HTML ファイル

こちらのページで使い方をまとめた Thymeleaf を利用しています。xmlns:th="http://www.thymeleaf.org" は IDE の警告表示を回避するための設定です。

src/main/resources/templates/home.html

ログインせずに表示できるホームページです。

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
  <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>

src/main/resources/templates/hello.html

ログインが必要なページです。ホームページからリンクされています。ログアウトするためのフォームも設置されています。#httpServletRequest.remoteUserHttpServletRequest#getRemoteUser() を利用するための Thymeleaf の記法です。

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
  <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>

src/main/resources/templates/login.html

ユーザー名とパスワードを POST するためのログインフォームです。クエリストリングで /login?error および /login?logout がパラメータとして渡された際に表示するメッセージを Thymelaf の param で判別して表示しています。

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
  <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>

LDAP サーバーを利用したログイン認証

本ページでは簡単のため、Java ソースコードにハードコーディングされた auth.inMemoryAuthentication() を利用しました。実際にアプリケーションを開発する際はその他の認証方法を利用します。例えば LDAP を利用する場合は auth.ldapAuthentication() を設定します。具体的なサンプルコードはこちらのページをご参照ください。

Related pages
    概要 こちらのページで開発環境の構築方法をまとめた Spring Boot における OAuth2 のサンプルコードをまとめます。こちらのページで和訳した Twitter API で利用されている OAuth 1.0A と区別します。こちらのページで簡単なサンプルをまとめた Spring Security プロジェクト配下の
    概要 こちらのページでは、Java のソースコードにハードコーディングしたユーザーとパスワードの情報をもとに、Spring Security でログインフォーム認証を行いました。本ページではユーザー認証を LDAP サーバーからの情報をもとに行います。 Spring LDAP が提供する LDAP クライアントを