引き続き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パッケージ指定をするだけで、すぐに基本的なセキュリティ機能を利用できるようになっているようです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
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ファイルを置くパスやファイルの拡張子を設定しています。後はロガーの設定です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
# 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のアプリケーションを起動します。以下の通り、特別な設定もありませんし、コントローラの定義もしていません。
1 2 3 4 5 6 7 8 9 10 11 |
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にブラウザからアクセスしてみます。
上記のようなスクリーンショットが表示されると思います。デフォルトの設定では、パス/login
に対するアクセスで、Spring Securityが提供してくれているログインフォームが返されるようになっています。
ちょっとした認証機能付のWebツールを作るのに、数ステップで実行できることが分かります。デフォルトのログイン認証では、メモリ上に保持しているユーザー、パスワードに対してマッチングするような動きになっています。ユーザー名とパスワードの指定をしない場合、ユーザー名「user」でパスワードはランダム生成されたUUIDが使われるので、上記の例ではapplication.properties
でパラメータの定義をしています。
参考 デフォルトのログインページ生成クラス
参考 デフォルトプロパティ設定
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
@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
が適用するという仕組みになっています。
参考
- FilterChainProxyクラスの実装
- SecurityFilterChainのデフォルト実装クラスDefaultSecurityFilterChain
Spring Bootによる自動設定
先に説明したとおり、spring-boot-security-starter
パッケージの依存関係をビルド定義に追加するだけで、Spring BootのAutoconfiguration機能により、Spring Security機能の自動設定が行われています。これは、DIコンテナの力によるものです。
Spring Securityでは、@EnableWebSecurity
で、セキュリティ機能を有効化していましたが、Spring Bootでは不要のようです。変わりにspring-boot-autoconfigure
に含まれるWebSecurityEnablerConfiguration
クラスが定義をしてくれています。ですので、アプリケーション開発者としては、WebSecurityConfigurerAdapter
を継承したクラスを作成し、セキュリティフィルタの設定等を行なっていけば良いようです。
1 2 3 4 5 6 7 |
@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
の中でハンドラメソッドが呼ばれます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
@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アプリケーションで行われているようなデータベースと連携した認証方法などについてまとめていきたいと思います。
参考リンク
- Spring Security Reference ( 5.0.7.RELEASE )
- Spring Boot Reference Guide ( 2.0.4.RELEASE ) – 28. Security
- GETTING STARTED – Securing a Web Application
- Spring Security Architecture
- Spring Security 使い方メモ 基礎・仕組み
- ↑かなり詳しい説明をしてくれている
コメント