Spring BootでSpring Security機能を使う ー 基礎

引き続きSpring Bootに関する投稿です。今回は、Spring Bootで認証機能(Spring Security)を使用する方法についてのメモです。

環境

Spring Boot 2.0.4.RELEASE

Spring BootでSecurity機能を使うには

Spring BootでSecurity機能を利用するには、spring-boot-starter-securityパッケージを依存関係に追加します。spring-boot-starter-securityを依存関係に追加すると、Webアプリケーションで必要となるセキュリティ機能を含んだspring-security-webパッケージが追加されます。後は、Spring Bootが、自動設定のためのパッケージspring-boot-autoconfigureの中で、Spring Security機能を使うための基本的なコンフィグレーションをしてくれます。そのため、starterパッケージ指定をするだけで、すぐに基本的なセキュリティ機能を利用できるようになっているようです。

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

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'

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

repositories {
    mavenCentral()
}


dependencies {
    compile('org.springframework.boot:spring-boot-starter-web')
    // SpringSecurityを使う
    compile('org.springframework.boot:spring-boot-starter-security')
    // SpringSecurityのtablibを使う
    compile('org.springframework.security:spring-security-taglibs')
    // JSPを使う設定
    compile('org.apache.tomcat.embed:tomcat-embed-jasper')
    // jstlを使う設定
    compile('javax.servlet:jstl')
    runtime('org.springframework.boot:spring-boot-devtools')
    compileOnly('org.projectlombok:lombok')
    testCompile('org.springframework.boot:spring-boot-starter-test')
    testCompile('org.springframework.security:spring-security-test')
}

上記のようなビルド定義を行ないgradleでコンパイルします。STSを使うと、上記のような定義ファイルとプロジェクトの雛形を作成してくれます。

続いて、application.propertiesにユーザ名やパスワードを指定します。その他、この例ではJSPを使うので、jspファイルを置くパスやファイルの拡張子を設定しています。後はロガーの設定です。

# JSP Setting
# templates are located in 'src/main/webapp/WEB-INF/jsp'.
spring.mvc.view.prefix=/WEB-INF/jsp/
spring.mvc.view.suffix=.jsp


# Spring Security User properties
# These properties are refered in authentication process.
spring.security.user.name=user
spring.security.user.password=password

# Logging Setting
logging.level.root=INFO
logging.level.org.springframework.web=DEBUG
logging.level.sample.web.form.security=DEBUG

以上の設定をして、Spring Bootのアプリケーションを起動します。以下の通り、特別な設定もありませんし、コントローラの定義もしていません。

package sample.web.form.security;

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

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

アプリケーションを起動したら、以下のURLにブラウザからアクセスしてみます。

    http://localhost:8080/login

上記のようなスクリーンショットが表示されると思います。デフォルトの設定では、パス/loginに対するアクセスで、Spring Securityが提供してくれているログインフォームが返されるようになっています。

ちょっとした認証機能付のWebツールを作るのに、数ステップで実行できることが分かります。デフォルトのログイン認証では、メモリ上に保持しているユーザー、パスワードに対してマッチングするような動きになっています。ユーザー名とパスワードの指定をしない場合、ユーザー名「user」でパスワードはランダム生成されたUUIDが使われるので、上記の例ではapplication.propertiesでパラメータの定義をしています。

参考 デフォルトのログインページ生成クラス

https://github.com/spring-projects/spring-security/blob/master/web/src/main/java/org/springframework/security/web/authentication/ui/DefaultLoginPageGeneratingFilter.java

参考 デフォルトプロパティ設定

@ConfigurationProperties(prefix = "spring.security")
public class SecurityProperties implements SecurityPrerequisite {
    ...

    public static class User {

        /**
         * Default user name.
         */
        private String name = "user";

        /**
         * Password for the default user name.
         */
        private String password = UUID.randomUUID().toString();
        ...
    }
}

Spring Securityの仕組み概要

Spring Securityは、サーブレットのフィルタの仕組みを利用し、セキュリティ機能を実装しています。特定のパスにマッチするリクエストに対し認証を要求したり、逆に静的リソースなど特定のパスにマッチするリクエストは制限しないといったことができます。

セキュリティフィルタの入り口となるDelegatingFilterProxyは、初回にspringSecurityFilterChainというBeanに処理を委譲します。springSecurityFilterChainは、セキュリティフィルタチェーンを構築しFilterChainProxyというフィルタを呼び出し元に返します。そして、初回以降、DelegatingFilterProxyはこのFilterChainProxyをdelegatorとし保持し、FilterChainProxyに処理を委譲するようになっています。

FilterChainProxyクラスは、複数のSecurityFilterChainを保持しており、SecurityFilterChainはリクエストに適用する一連のFilterを保持しています。SecurityFilterChainは、自分自身がどのリクエストに対してFilter群を実行するかを判別するため、RequestMatcherを使ってマッチング処理を行ないます。FilterChainProxyクラスは、SecurityFilterChainを順に辿り、最初にマッチングしたSecurityFilterChainが適用するという仕組みになっています。

参考

Spring Bootによる自動設定

先に説明したとおり、spring-boot-security-starterパッケージの依存関係をビルド定義に追加するだけで、Spring BootのAutoconfiguration機能により、Spring Security機能の自動設定が行われています。これは、DIコンテナの力によるものです。

Spring Securityでは、@EnableWebSecurityで、セキュリティ機能を有効化していましたが、Spring Bootでは不要のようです。変わりにspring-boot-autoconfigureに含まれるWebSecurityEnablerConfigurationクラスが定義をしてくれています。ですので、アプリケーション開発者としては、WebSecurityConfigurerAdapterを継承したクラスを作成し、セキュリティフィルタの設定等を行なっていけば良いようです。

@ConditionalOnBean(WebSecurityConfigurerAdapter.class)
@ConditionalOnMissingBean(name = BeanIds.SPRING_SECURITY_FILTER_CHAIN)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
@EnableWebSecurity
public class WebSecurityEnablerConfiguration {

}

Spring Securityは、サーブレットのフィルタの仕組みを利用しています。Spring Bootは、コンテナを起動する時、ServletContextInitializerインターフェースを実装しているDelegatingFilterProxyRegistrationBeanを介して、Spring SecurityのBean名springSecurityFilterChainで登録されているフィルタをサーブレットフィルタとしてコンテナに登録しています。これにより、サーブレットのフィルタチェーンにSpring Securityのフィルタが登録され利用可能になっています。

DelegatingFilterProxyRegistrationBeanは、ServletContextInitializerインターフェースの実装クラスの1つで、コンテナ初期化時にServletWebServerApplicationContextの中でハンドラメソッドが呼ばれます。

@Configuration
@ConditionalOnWebApplication(type = Type.SERVLET)
@EnableConfigurationProperties(SecurityProperties.class)
@ConditionalOnClass({ AbstractSecurityWebApplicationInitializer.class,
        SessionCreationPolicy.class })
@AutoConfigureAfter(SecurityAutoConfiguration.class)
public class SecurityFilterAutoConfiguration {

    private static final String DEFAULT_FILTER_NAME = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME;

    @Bean
    @ConditionalOnBean(name = DEFAULT_FILTER_NAME)
    public DelegatingFilterProxyRegistrationBean securityFilterChainRegistration(
            SecurityProperties securityProperties) {
        DelegatingFilterProxyRegistrationBean registration = new DelegatingFilterProxyRegistrationBean(
                DEFAULT_FILTER_NAME);
        registration.setOrder(securityProperties.getFilter().getOrder());
        registration.setDispatcherTypes(getDispatcherTypes(securityProperties));
        return registration;
    }

    ...
    
}

まとめ

Spring Bootは、簡単にSpring Securityを使えるようコンフィグレーションを定義してくれているため、spring-boot-security-starterパッケージを依存に追加するだけで、すぐに基本的な機能を利用可能になります。

次回は、認証まわりの仕組みや実際のWebアプリケーションで行われているようなデータベースと連携した認証方法などについてまとめていきたいと思います。

参考リンク

 

byebyehaikikyou

日記やIT系関連のネタ、WordPressに関することなど様々な事柄を書き付けた雑記です。ITエンジニア経験があるのでプログラミングに関することなどが多いです。

シェアする

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

コメントする

Translate »