springboot」タグアーカイブ

Spring BootでSpring Security機能を使う ー データベースを使った認証

この記事は【2018年9月8日】と作成から2年以上経っているため、記事の内容が古い可能性があります。最新の情報を合わせてご確認されることを推奨いたします。

前回、Spring BootでSpring Security機能を有効化する方法について見てきました。

https://debug-life.net/entry/3189

次は、Spring BootでSpring Securityの認証機能の1つであるデータベースを使った認証の仕組みについて見ていきます。

Spring Securityの認証処理の仕組み

Webアプリケーションのセキュリティ機能を提供してくれているspring-security-webでは、サーブレットフィルタの仕組みを利用し、認証機能が実現されていることを見てきました。では、実際にフィルタからどのように認証処理が行われているのでしょうか?

仕組みを俯瞰するため、まずは以下に主要なクラスの関連図(概要のため省略あり)をまとめてみます。

概要をまとめると、以下のようになっているようです。

  • 認証処理は、AuthenticationManagerが受け付ける。AuthenticationManagerはインターフェースであり、実装クラスとしてProviderManagerがある。
  • ProviderManagerは、複数の認証プロバイダAuthenticationProvider(実際に認証処理を担当する)を管理しており、認証の問い合わせを受けると、各認証プロバイダに認証処理を委譲する。
  • 認証に成功すると、Authenticationオブジェクトが返される。Authenticationはインターフェースであり、実装クラスはxxAuthenticationTokenのように命名されている。例えば、フォーム認証ではUsernamePasswordAuthenticationTokenが使われている。

と、このように認証マネージャ(実装クラスProviderManager)が複数の認証プロバイダ(具体的な認証処理を行なうクラス達)に認証処理を委譲するように抽象化されていることが分かります。そして、spring-securityに限らずですが、この抽象化がユーザ独自機能を含めたカスタマイズを可能にしています。

Spring Bootでデータベース認証を実装してみる

Spring Bootの大きな特徴は、様々な設定を自動化しすぐに所望する機能を使用することができるような仕組みの提供(autoconfiguration)でした。Spring Bootはデータベース機能(spring-jdbc)を使用するためのコンフィグレーションを提供してくれているため、それを利用することでデータベース認証機能を用意に実装することができます。

ここでは、spring-jdbcを使って組み込みデータベースでの簡単なユーザ管理機能を実装してみたいと思います。

依存関係の定義

今回のサンプルでは、組み込みデータベースのH2を使うこととします。また、データアクセス機能には、spring-jdbcを使います。

UserDetailsの実装

まずは、ユーザ情報を提供する機能について見ていきます。

インターフェースは以下のようになっていますが、今回は既にSpringにある実装のorg.springframework.security.core.userdetails.Userクラスで代用することとします。従って、ここでは簡単のためUserDetailsの実装クラスは作成しません。

インターフェースを見ればメソッド名からどういう実装をすべきか判断することができると思います。ユーザ名、パスワード、ロール、アカウント有効無効、ロック状態や有効期限などの情報を返すクラスを実装すれば良いことが分かります。

参考 

UserServiceDetailsの実装

ユーザ情報に関する操作機能を提供します。メイン機能のインターフェースは以下のようになっており、ユーザ名を引数で受け取り、ユーザ情報を返す仕様となっています。

今回の例では、UserDetails同様にSpringにあるデフォルト実装を利用することとします。今回はデータベース認証機能の実装が目的なので、最初のクラス図で挙げたorg.springframework.security.provisioning.JdbcUserDetailsManagerを使うことにします。このクラスは、JdbcTemplateを使ったデータアクセス機能を提供する抽象クラスJdbcDaoSupportを継承していています(具体的にはJdbcDaoSupportの具象クラスであるJdbcDaoImplを継承)。また、ユーザに関する基本的なCRUD機能の仕様であるUserDetailsManagerインターフェースを実装しています。従って、JdbcUserDetailsManagerクラスを使うことで、ユーザに関する基本的なCRUD機能を享受することができます。

参考 

データベースコンフィグレーション

上記までで、ユーザ情報やユーザ情報操作の基本的な操作を準備することができました。と言っても、デフォルト実装を使用するという方針を定めただけでプログラムは書いていません。

続いて、spring-jdbc機能の設定が必要になりますが、コンフィグレーションはSpring BootのAutoConfigurationが行なってくれます。DataSourceなどのBean定義は基本的には不要で、使用するデータベースの依存関係の追加やapplication.propertiesに必要な設定を記述するだけで、spring-jdbcが提供してくれる機能をインジェクションして使用できるようになっています。

application.properites

データベースに関連する設定は、最後のセクションです。起動時にスキーマ作成と初期データの投入を行うための設定及び、H2 Consoleを使うための設定をしています。

データベースコンフィグレーション

以下の2つを定義します。

上記例では、UserDetailsServiceとしてJdbcUserDetailsManagerを定義しています。また、PasswordEncoderも同様に使いたいのでここで定義していますが、PasswordEncoderFactories.createDelegatingPasswordEncoder()で直接PasswordEncoderの実装クラスを指定していません。プリフィックス型({xxx})がある場合、別のサポートする実装クラスに照合処理を委譲できるようにしています。例えば、{noop}xxxxでは、NoOpPasswordEncoderが使われます(ただし、NoOpPasswordEncoderは@Deprecatedです、実際のサービスでは別のセキュアな実装を使います)。

なお、spring-boot-starter-jdbcでは、デフォルトでHikariDataSourceが使われます。

スキーマとデータ

起動時に定義する内容です。JdbcUserDetailsManagerクラスが想定しているクエリに合わせて、以下のように定義しています。(アカウントのロックや期限などの情報は省略しています)

セキュリティコンフィグレーション

続いて、セキュリティ機能の設定を確認しておきます。今回は、簡易なユーザ管理機能を作るという目的のため、/userというパスに認証・認可を要求するように設定します。

フォーム

ユーザ名とパスワードと受け取るだけの単純なクラスとします。

リポジトリクラス

データアクセスのためのクラスを作成します。ここでは、UserRepositoryとします。リポジトリパターンではインターフェースを定義するかと思いますが、今回は簡単のためインターフェース定義は省略します。

以下サンプルでは、CRUD機能はUserDetailsMangerに委譲するようにしています。

コントローラとビュー

最後に、コントローラとビューを作成します。

ログインフォームは、Spring Securityのデフォルトの機能を使用しています。

動作画面

以下のURLにアクセスすると、ログインフォームへリダイレクトされます。

   http://localhost:8080/user/

このサンプルプログラムでは、admin/adminでログインできます。ログインすると以下のような簡素な画面が表示されます。

H2 Console画面も以下のように表示できます。

まとめ

  • Spring Bootでは、AutoConfiguration機能のおかけで、application.propertiesで最低限の設定をするだけで、spring-jdbcの基本的なコンフィグレーションが行われ、簡単にデータアクセス機能を利用したspring-securityのデータベース認証処理を行なうことができます。
  • spring-boot-starter-jdbcでは、デフォルトのデータソースとしてHikariDataSourceが使われます。
  • UserDetailsServiceの実装クラスであるJdbcUserDetailsManagerを使えば、ユーザに関する基本的なCRUD操作が行えます。
  • PasswordEncoderは、デフォルトでBCryptPasswordEncoderが使われます。

今回使用したサンプルプログラムは以下です。

https://github.com/moritoru81/spring-boot-misc/tree/master/spring-security-database-authentication

参考リンク

 

 

Spring徹底入門 Spring FrameworkによるJavaアプリケーション開発
株式会社NTTデータ
翔泳社
売り上げランキング: 37,650

 

Spring Boot 2 プログラミング入門
掌田津耶乃
秀和システム
売り上げランキング: 7,583

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

この記事は【2018年8月25日】と作成から2年以上経っているため、記事の内容が古い可能性があります。最新の情報を合わせてご確認されることを推奨いたします。

引き続き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パッケージ指定をするだけで、すぐに基本的なセキュリティ機能を利用できるようになっているようです。

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

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

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

アプリケーションを起動したら、以下の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

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

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を継承したクラスを作成し、セキュリティフィルタの設定等を行なっていけば良いようです。

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

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

まとめ

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

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

参考リンク

 

Spring Bootでのサーブレットフィルタ設定

この記事は【2018年8月14日】と作成から2年以上経っているため、記事の内容が古い可能性があります。最新の情報を合わせてご確認されることを推奨いたします。

引き続きSpring Bootに関する投稿です。今回は、Spring Bootでサーブレットフィルタを設定するにはどうするか?、です。

環境

  • spring-boot-2.0.4.RELEASE
  • spring-boot-starter-web
  • Embedded Tomcat 8.5.32

組み込みのTomcatコンテナで動作させる前提です。

フィルタの登録方法

Spring Bootでは、web.xmlのような設定ファイルは不要で、コントローラやフィルタなどのクラスを実装し、アノテーションやBean定義を行なうだけで、容易にSpring Bootに追加したい機能(今回はフィルタ)を認識させることができます。

さて、Spring Bootでフィルタを登録する方法ですが、1〜3で利用頻度もしくは一般的であろう順(著者感覚)に整理してみました。

1. FilterRegistrationBeanのBean定義

Spring Bootでは、Servlet、Filter、Listenerに対し、それぞれServletRegistrationBeanFilterRegistrationBeanServletListenerRegistrationBeanというInitializerクラスが用意されています。

これらのクラス群は、ServletContextInitializerインタフェースを実装しており、ServletContextの初期化時に呼ばれ、各種コンフィグレーションを行なうようになっています。そして、各種BeanはServletContextInitializerBeansコンテナ(ここではコレクションのデータコンテナを意味する)に登録されており、TomcatStarteronStartupコールバックでコンフィグレーションが実行されます。

MyFilter、MyFilter2クラスは、通常のフィルタ定義と同様で、javax.servlet.Filterインターフェースを実装したクラスとして定義します。

参考 

2. FilterのBean定義

Servlet3.0で@WebFilterでフィルタ定義ができるようになりました。通常Spring Bootで組み込みコンテナを使って起動した場合、この@WebFilter定義は無視されます。しかし、これらのアノテーションを使ったクラス(ライブラリなど)をアプリケーションでもそのまま利用したい場合、@ServletComponentScanをつけると認識してくれるようです。

@ServletComponentScanを付与した場合、ServletComponentHandlerを継承している各種HandlerクラスであるWebFilterHandlerWebListenerHandlerWebServletHandlerで処理されます。@ServletComponentScanには、スキャンのベースとなるパッケージを指定します。@ServletComponentScanの指定がない場合は、アノテーションが指定されたクラスのパッケージからスキャンされます。

フィルタクラスに@WebFilterを指定します。

参考 

3. ServletContextInitializerのBean定義

フィルタ以外にもServletContextの初期化時に何らかの処理をしたい場合には、独自のServletContextInitializerを定義することができます。この場合1と同様、ServletContextInitializerBeansに登録され、コンテナ起動時にスタートアップコールバックが呼ばれます。コールバックの引数で、ServletContextオブジェクトが渡されるので、その中で必要な設定を行なう方法も可能だと思います。

以下は直接Servlet APIを呼んで、InitParameterやFilterを登録する例です。

参考 

参考リンク

Spring BootでのWebMvcのJavaコンフィグレーション

この記事は【2018年8月10日】と作成から2年以上経っているため、記事の内容が古い可能性があります。最新の情報を合わせてご確認されることを推奨いたします。

最近、個人的にSpring Bootを使ったWebアプリケーション開発について学んでいます。ちょっとしたWebベースのアプリケーションをJavaで開発したいと思い、Spring Bootであればサクッと作れそうと思ったからです。。が、私自身Spring BootどころかSpringの知識さえも余りないので、「Spring徹底入門」や公式ドキュメント及びソースリーディングしながら、写経とデバッグで動きを追いながら、少しずつ動きや仕組みについて理解を進めているところです。

今回は、Spring BootでWebMvcベースのアプリケーション開発を行なう時、Javaベースのコンフィグレーションってどうするんだっけ?と、そもそも仕組み周りから理解できていなかったので整理してみました。

Auto-configuration

Spring Bootには、Auto-configurationという、最小限の設定でSpringアプリケーションを容易に構築できる仕組みがあります。例えば、必要な条件が満たされる場合(例えば特定のクラスがクラスパス上に存在しているまたは存在していない、など)にBean定義が有効になるといった具合です。以下は、CassandraAutoConfigurationクラスの一例で、アノテーション@ConditionalOnClassで、クラスパスにorg.apache.catalina.Clusterクラスが存在する場合に自動設定定義が有効化されるようになっています。

出典 https://github.com/spring-projects/spring-boot/blob/master/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cassandra/CassandraAutoConfiguration.java

Spring Bootでは、著名な様々なソフトウェアの自動設定を行なうAutoConfigureクラスが提供されています。以下は、spring-bootのautoconfigureプロジェクトのリポジトリですが、cassandraやmongo、solrなどのAutoConfigurationクラスが用意されているのが分かります。

https://github.com/spring-projects/spring-boot/tree/master/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure

AutoConfigure機能は、spring-boot-autoconfigureというプロジェクトで定義されており、spring-boot-starterプロジェクトをライブラリとして追加すると、依存ライブラリとして追加されます。

さて、Spring BootでWebアプリケーション開発を行なうためのstarterライブラリとして、spring-boot-starter-webがあります。starter-webの依存ライブラリには、spring-webspring-webmvcがあり、Spring MVCを使ったWebアプリケーション開発のベースが整います。

以下は、Spring Bootのバージョン2.0.4.RELEASEで、spring-boot-starter-webを依存関係のcompileに指定した場合の依存関係グラフです。

spring-webspring-webmvc、そしてspring-boot-autoconfigureも依存ライブラリとしてクラスパスに追加されます。そして、webmvcで必要となるコンフィグレーションもautoconfigureライブラリに内包されており、すぐにSpring MVCでWebアプリケーション開発が行えるようになっているようです。

Spring BootでMVCのWebアプリケーション開発をするための下地は、STS(Spring Tool Suite)を使ってプロジェクト「Spring Boot>Spring Starter Project」作成をすると、すぐに構築できます。

組み込みたい依存ライブラリを選択します。

また、同様な事は、以下のウェブページからも可能です。

https://start.spring.io

@EnableWebMvc

SpringでのWebMvcコンフィグレーション

Springでは、アノテーションorg.springframework.web.servlet.config.annotation.EnableWebMvcをクラス定義に付与する事で、Spring MVCが提供してくれているコンフィグレーションクラスがインポートされ、必要となるコンポーネントのBean定義が自動で行われるようになっています。

EnableWebMvcの定義を見ると、アノテーション@Importで、org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfigurationクラスがインポートされるようになっています。このクラスは、基本的なコンフィグレーションを担うWebMvcConfigurationSupportクラスを継承しています。また、WebMvcConfigurerCompositeクラスをメンバ変数に持ち、WebMvcConfigurerオブジェクトらにコンフィグレーションを委譲するようになっています。WebMvcConfigurerオブジェクトは、@Autowiredでインジェクトされるようになっています。

以下、各クラスの実装の抜粋です。(Branch 5.0.x)

参考 https://github.com/spring-projects/spring-framework/blob/5.0.x/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/DelegatingWebMvcConfiguration.java

参考 https://github.com/spring-projects/spring-framework/blob/5.0.x/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurerComposite.java

従って、アノテーション@EnableWebMvc@Configurationクラスのいずれか1つ(@Configurationが付与されるクラスは複数存在し得るため)に付与されており、クラスパス上に@Configurationを付与したWebMvcConfigurerインターフェース実装のクラスを設置する事で、コンフィグレーションのカスタマイズができるようになっているようです。

参考 https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/servlet/config/annotation/EnableWebMvc.html

最新のSpring(5.0)より前のバージョンでは、WebMvcConfigurerAdapterクラスを継承していたようですが、5.0以降ではInterfaceのdefault実装を使用しているため、直接WebMvcConfigurerインターフェースを実装したクラスを定義できるようになっています。

Spring BootのWebMvcコンフィグレーション

Spring Bootのautoconfigureライブラリでは、

org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfigurationが、@EnableWebMvc相当の処理を担当しているようです。

WebMvcAutoConfigurationAdapterクラスで、EnableWebMvcConfigurationクラスがインポートされ、EnableWebMvcConfigurationクラスは内部クラスとして定義されています。そして、EnableWebMvcConfigurationクラスはDelegatingWebMvcConfigurationクラスを継承しているため、DelegatingWebMvcConfigurationクラスのように振る舞います。

このことから、Spring Bootでは@EnableWebMvcを明示的に指定しなくとも、@Configurationを付与したWebMvcConfigurerインターフェースを実装したクラスをコンフィグレーションクラスとしてクラスパス上に配置していれば良いようです。WebMvcConfigurationSupportクラスを継承したクラスでコンフィグレーションを記述した場合は、EnableWebMvcConfigurationクラスはインポートされません。SpringのDocsにもあるように、WebMvcConfigurerインターフェースによるカスタマイズを使用しない場合は、WebMvcConfigurationSupportクラスかDelegatingWebMvcConfigurationクラスを直接継承し、コンフィグレーションを記述することになるようです。

If WebMvcConfigurer does not expose some more advanced setting that needs to be configured consider removing the @EnableWebMvc annotation and extending directly from WebMvcConfigurationSupport or DelegatingWebMvcConfiguration, e.g.:

https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/servlet/config/annotation/EnableWebMvc.html

コンフィグレーションをカスタマイズしたい場合、通常はWebMvcConfigurerインターフェースを実装したコンフィグレーションクラスを定義すればよいと思います。デフォルトで、すぐにアプリケーション開発ができるような設定がなされた状態となっているからです。

参考リンク

参考書籍

Spring徹底入門 Spring FrameworkによるJavaアプリケーション開発
株式会社NTTデータ
翔泳社
売り上げランキング: 7,987

本書籍で一通り学習しましたが、ページ数が豊富で幅広くトピックが取り上げられているのでお勧めです。Java言語そのものの知識は必要なので、『パーフェクトJava』などで基礎は学習しておくと良いです。

改訂2版 パーフェクトJava
井上 誠一郎 永井 雅人
技術評論社
売り上げランキング: 210,028
パーフェクト Java EE
パーフェクト Java EE

posted with amazlet at 18.08.07
井上 誠一郎 槙 俊明 上妻 宜人 菊田 洋一
技術評論社
売り上げランキング: 147,078