SlideShare a Scribd company logo
1 of 22
Download to read offline
1
今こそ知りたいSpring Security
2020/12/17
日本Springユーザ会
土岐 孝平
自己紹介
• 土岐 孝平
• 合同会社 現場指向
• Webアプリ「メモラキー」の運営
• システム開発の支援
• 研修の講師
• 書籍の執筆
2
[改訂新版]Spring入門https://www.memorarchy.com
想定する聴講者
• なんとなく使ってはいるが、裏で何が起こってるのか
わからず、もやもやしている
• 少し触ったけど、難しそうなので自前にしようか悩ん
でいる
3
Spring Securityに触ったことがある方が前提です
本セッションの目的
• Spring Securityが裏で何をやっているかを知って、
問題が起きたときのデバッグや、カスタマイズ方法
の調査を円滑にする
• キーとなる以下の2つを抑える
– Security Filter Chain
– Security Context
4
網羅的な機能の説明や、設定ノウハウの説明は行いません
Security Filter Chainとは?
• Spring Securityが提供するFilter※の繋がり
• Servlet Filterの仕組みを使って処理を挟み込む
• 各Filterは、認証、URLパスの認可、CSRF防止などの役割
を持つ
5
※ 個々のFilterは
ServletのFilterイン
タフェースを実装し
ているが、Servletコ
ンテナに登録されて
いる訳ではない
Filter1
FilterX
DispatcherServlet
Delegating
FilterProxy
ブラウザ
・・
・
・・・
Controller
・・
・
ServletのFilter Chain
★Security Filter
Chain
Filter2
Spring MVCのサーブ
レット
主なFilter
6
クラス名 役割
CsrfFilter CSRFトークンの発行やチェックを行う
HeaderWriterFilter セキュリティ関連のレスポンスヘッダを
設定する
BasicAuthenticationFilter Basic認証を行う
UsernamePasswordAuthenticationFilter フォーム認証を行う
ExceptionTranslationFilter 後続の処理で発生した認証・認可の例
外をキャッチしてハンドリング(エラー画
面に遷移など)する
FilterSecurityInterceptor URLのパスの認可を行う
SecurityContextPersistenceFilter 「Security Context」を用意して、HTTP
セッションやThreadLocalに格納する
次ページで説明
Security Context
• 認証したユーザ情報(IDや権限など)を格納するオブジェクト
• HTTPセッションに保持されるため、リクエストを跨ってユー
ザ情報を参照できる
• ThreadLocal(スレッド毎にデータを管理してくれる)にも保持
されるため、リクエスト(スレッド)の処理内の任意のタイミング
でユーザ情報を参照可能
– Controllerの引数で受けとる
– 画面にユーザ情報を表示するときに参照
– staticメソッドでプログラムの任意の箇所で参照
• SecurityContextHolder.getContext()
– 認可時(URLのパス、メソッド、画面内の表示非表示)に参照
7
ThreadLocal
ThreadLocalとSecurity Contextのイメージ
8
Aさん
Bさん
Bさんの
スレッド
Bさんの
Security Context
Aさんのリクエスト(スレッド)の処理
Bさんのリクエスト(スレッド)の処理
Aさんの
スレッド
Aさんの
Security Context
Security Filter Chainの作成
• WebSecurityConfigurerAdapter を継承して
@EnableWebSecurityを付けたJavaConfigのクラス
(@Configurationを付けたクラス)を作成する
• @EnableWebSecurityがインポートしている
WebSecurityConfigurationクラスの中で、Security Filter
Chainのオブジェクトが作成される
• 標準的なFilterが自動で登録されるので、メソッドをオーバー
ライドして個別の設定を行う 9
@Configuration@Configuration
@EnableWebSecurity
public class SampleSecurityConfig extends WebSecurityConfigurerAdapter {
}
個別の設定のサンプル
10
@Configuration
@EnableWebSecurity
public class SampleSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.mvcMatchers("/admin/**").hasAuthority("ADMIN")
.anyRequest().authenticated().and()
.httpBasic();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
PasswordEncoder encoder
= PasswordEncoderFactories.createDelegatingPasswordEncoder();
auth
.inMemoryAuthentication()
.withUser("foo").password(encoder.encode("passfoo")).authorities("ADMIN").and()
.withUser("bar").password(encoder.encode("passbar")).authorities("USER");
}
}
「/admin」 で始まるパスは「ADMIN」権限が
必要、それ以外は認証されてればOK
Basic認証を有効にする
「foo」ユーザは「ADMIN」権限、「bar」ユーザは
「USER」権限という認証情報をメモリ上に保管
出来上がった主なオブジェクト
11
Authentication
Manager
UserDetailsService
AccessDecision
Manager
Dispatcher
Servlet
Delegating
FilterProxy
ブラウザ
・・
・
・・
・
Controller
ServletのFilter Chain
★Security Filter Chain
ID・パスワードのチェックを
行う。認証情報は
UserDetailsServieから取得
権限のチェックを行う
認証情報を取得。今回はメ
モリ上から取得
URLのパスの認可を行う
BasicAuthenticationFilter
ExceptionTranslationFilter
SecurityContextPersistenceFilter
FilterSecurityInterceptor
Basic認証を行う
Security Filter Chainの動作イメージ
• 認可が必要なURLに初回アクセスしたとき
– ※主なFilterに絞っています
12
BasicAuthenticationFilter
ExceptionTranslationFilter
SecurityContextPersistenceFilter
FilterSecurityInterceptor
DispatcherServlet
リクエスト(/admin/foo) レスポンス
HTTPセッションにSecurity Context
がないため、新しく用意する。
用意したSecurity Contextを、
ThreadLocalに入れる
Authorization ID
Context
AuthorizationヘッダからユーザID・
パスワードを取得して認証する。
OKならユーザ情報をSecurity
Contextに入れる
スルー
URLパスに設定された権限と、
Security Contextのユーザ情報の権
限を比較する。OKなら後続の処理
を呼び出す
スルー
例外が投げられた訳
ではないのでスルー
スルー
ユーザ情報入りの
Security ContextをHTTP
セッションに入れる
フォーム認証のサンプル
13
@Configuration
@EnableWebSecurity
public class SampleSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.mvcMatchers("/admin/**").hasAuthority("ADMIN")
.anyRequest().authenticated().and()
.formLogin()
.loginPage("/login").permitAll()
.loginProcessingUrl("/login")
.usernameParameter("username").passwordParameter("password")
.failureUrl("/login?error");
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
・・・ 省略
}
}
フォーム認証を有効にする
ログイン画面のパス。未認証のユーザ
を自動的に遷移させる
認証リクエストのパス。POST前提
認証リクエストに乗せるユーザIDとパス
ワードのパラメータ名ログイン失敗時に遷移
するパス
ログイン画面のサンプル
14
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<body>
<form th:action="@{/login}" method="post">
<input type="text" name="username" />
<input type="text" name="password" />
<input type="submit" value="送信" />
</form>
</body>
</html>
POSTメソッドを指定
※テンプレートエンジンのThymeleafを使用
Security Filter Chainの動作イメージ1/3
• 未認証のユーザが、認可が必要なURLにアクセス
15
UsernamePasswordAuthenticationFilter
ExceptionTranslationFilter
SecurityContextPersistenceFilter
FilterSecurityInterceptor
DispatcherServlet
ログイン画面にリダイレクトHTTPセッションにSecurity Context
がないため、新しく用意する。
用意したSecurity Contextを、
ThreadLocalに入れる
認証のリクエストでは無いので
スルー
リクエスト(/admin/foo)
スルー
未認証なので、
AccessDeniedExceptionをスロー
AccessDeniedExceptionをキャッチ
して、ログイン画面にリダイレクト
するレスポンスを設定。その際、
リクエストの内容をHTTPセッショ
ンに格納する(ログイン後に自動
で遷移するため)
スルー
空のSecurity Contextを
HTTPセッションに入れる。
Security Filter Chainの動作イメージ2/3
• 認証リクエストを送信
16
UsernamePasswordAuthenticationFilter
ExceptionTranslationFilter
SecurityContextPersistenceFilter
FilterSecurityInterceptor
/admin/fooにリダイレクトリクエスト(POSTの/login)
HTTPセッションから空のSecurity
Contextを取得して、ThreadLocal
に入れる。
認証リクエストだと判断して、リク
エストパラメータのID・パスワード
で認証する。認証したユーザ情
報をSecurity Contextに入れる。
HTTPセッションに格納しておいた
リクエストにリダイレクトするレス
ポンスを設定。
DispatcherServlet
ユーザ情報が入った
Security ContextをHTTP
セッションに入れる。
Security Filter Chainの動作イメージ3/3
• /admin/fooにアクセス
17
SecurityContextPersistenceFilter
FilterSecurityInterceptor
レスポンスリクエスト(/admin/foo)
HTTPセッションからSecurity
Context(ユーザ情報入り)を取得
して、ThreadLocalに入れる。
DispatcherServlet
ユーザ情報が入った
Security ContextをHTTP
セッションに入れる。
UsernamePasswordAuthenticationFilter
ExceptionTranslationFilter
認証のリクエストでは無いので
スルー
スルー
URLパスに設定された権限と、
Security Contextのユーザ情報の
権限を比較する。OKなら後続の処
理を呼び出す
スルー
例外が投げられた訳
ではないのでスルー
スルー
Security Filter Chainのログ 1/2
• どのFilterが、どの順番で動いたかをログに出力す
ることが可能
– デバッグに便利
• 設定方法
– ロガーの「org.springframework.security」をDEBUGレベルに
する
– application.propertiesでの設定例
18
logging.level.org.springframework.security=DEBUG
Security Filter Chainのログ 2/2
• 出力例
– 未認証のユーザが、認可が必要なURLにアクセスしたと
きのログ(抜粋)
19
/admin/foo at position 1 of 12 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
/admin/foo at position 2 of 12 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
No HttpSession currently exists
No SecurityContext was available from the HttpSession: null. A new one will be created.
/admin/foo at position 3 of 12 in additional filter chain; firing Filter: 'HeaderWriterFilter'
/admin/foo at position 4 of 12 in additional filter chain; firing Filter: 'CsrfFilter'
/admin/foo at position 5 of 12 in additional filter chain; firing Filter: 'LogoutFilter'
Request 'GET /admin/foo' doesn't match 'POST /logout'
/admin/foo at position 6 of 12 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter'
Request 'GET /admin/foo' doesn't match 'POST /login'
/admin/foo at position 7 of 12 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
saved request doesn't match
/admin/foo at position 8 of 12 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
/admin/foo at position 9 of 12 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
/admin/foo at position 10 of 12 in additional filter chain; firing Filter: 'SessionManagementFilter'
/admin/foo at position 11 of 12 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
/admin/foo at position 12 of 12 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
Secure object: FilterInvocation: URL: /admin/foo; Attributes: [hasAuthority('ADMIN')]
Voter: org.springframework.security.web.access.expression.WebExpressionVoter@7d30e6, returned: -1
o.s.s.w.a.ExceptionTranslationFilter : Access is denied (user is anonymous); redirecting to authentication entry point
Filterの数と処理
準が表示われる
特別な処理が行われた
らログにでる
さいごに
• Spring Securityの裏の動きのイメージが沸いて、デ
バッグやカスタマイズの作業がし易くなれば幸いで
す。
• おすすめのサイト
– Spring Securityのマニュアルの「The Big Picture」の章
• https://docs.spring.io/spring-
security/site/docs/current/reference/html5/#servlet-
architecture
20
21
ご清聴ありがとうございました
22
ライセンスについて
• JSUGマスコットアイコン(本スライド左下)が残されている場合に限り、本作品(またそれを元にした派生
作品)の複製・頒布・表示・上演を認めます。
• 非商用目的に限り、本作品(またそれを元にした派生作品)の複製・頒布・表示・上演を認めます。
• 本作品のライセンスを遵守する限り、派生作品を頒布することを許可します。

More Related Content

What's hot

Spring3.1概要 データアクセスとトランザクション処理
Spring3.1概要 データアクセスとトランザクション処理Spring3.1概要 データアクセスとトランザクション処理
Spring3.1概要 データアクセスとトランザクション処理
土岐 孝平
 
オブジェクト指向の設計と実装の学び方のコツ
オブジェクト指向の設計と実装の学び方のコツオブジェクト指向の設計と実装の学び方のコツ
オブジェクト指向の設計と実装の学び方のコツ
増田 亨
 

What's hot (20)

怖くないSpring Bootのオートコンフィグレーション
怖くないSpring Bootのオートコンフィグレーション怖くないSpring Bootのオートコンフィグレーション
怖くないSpring Bootのオートコンフィグレーション
 
Javaのログ出力: 道具と考え方
Javaのログ出力: 道具と考え方Javaのログ出力: 道具と考え方
Javaのログ出力: 道具と考え方
 
Getting Started GraalVM / GraalVM超入門 #jjug_ccc #ccc_c2
Getting Started GraalVM / GraalVM超入門 #jjug_ccc #ccc_c2Getting Started GraalVM / GraalVM超入門 #jjug_ccc #ccc_c2
Getting Started GraalVM / GraalVM超入門 #jjug_ccc #ccc_c2
 
はまる!JPA(初学者向けライト版)
はまる!JPA(初学者向けライト版)はまる!JPA(初学者向けライト版)
はまる!JPA(初学者向けライト版)
 
Spring Boot × Vue.jsでSPAを作る
Spring Boot × Vue.jsでSPAを作るSpring Boot × Vue.jsでSPAを作る
Spring Boot × Vue.jsでSPAを作る
 
Spring3.1概要 データアクセスとトランザクション処理
Spring3.1概要 データアクセスとトランザクション処理Spring3.1概要 データアクセスとトランザクション処理
Spring3.1概要 データアクセスとトランザクション処理
 
世界一わかりやすいClean Architecture
世界一わかりやすいClean Architecture世界一わかりやすいClean Architecture
世界一わかりやすいClean Architecture
 
Unified JVM Logging
Unified JVM LoggingUnified JVM Logging
Unified JVM Logging
 
ぱぱっと理解するSpring Cloudの基本
ぱぱっと理解するSpring Cloudの基本ぱぱっと理解するSpring Cloudの基本
ぱぱっと理解するSpring Cloudの基本
 
決済サービスのSpring Bootのバージョンを2系に上げた話
決済サービスのSpring Bootのバージョンを2系に上げた話決済サービスのSpring Bootのバージョンを2系に上げた話
決済サービスのSpring Bootのバージョンを2系に上げた話
 
Spring Bootの本当の理解ポイント #jjug
Spring Bootの本当の理解ポイント #jjugSpring Bootの本当の理解ポイント #jjug
Spring Bootの本当の理解ポイント #jjug
 
ソーシャルゲーム案件におけるDB分割のPHP実装
ソーシャルゲーム案件におけるDB分割のPHP実装ソーシャルゲーム案件におけるDB分割のPHP実装
ソーシャルゲーム案件におけるDB分割のPHP実装
 
さくっと理解するSpring bootの仕組み
さくっと理解するSpring bootの仕組みさくっと理解するSpring bootの仕組み
さくっと理解するSpring bootの仕組み
 
単なるキャッシュじゃないよ!?infinispanの紹介
単なるキャッシュじゃないよ!?infinispanの紹介単なるキャッシュじゃないよ!?infinispanの紹介
単なるキャッシュじゃないよ!?infinispanの紹介
 
SPAセキュリティ入門~PHP Conference Japan 2021
SPAセキュリティ入門~PHP Conference Japan 2021SPAセキュリティ入門~PHP Conference Japan 2021
SPAセキュリティ入門~PHP Conference Japan 2021
 
WebSocket / WebRTCの技術紹介
WebSocket / WebRTCの技術紹介WebSocket / WebRTCの技術紹介
WebSocket / WebRTCの技術紹介
 
オブジェクト指向の設計と実装の学び方のコツ
オブジェクト指向の設計と実装の学び方のコツオブジェクト指向の設計と実装の学び方のコツ
オブジェクト指向の設計と実装の学び方のコツ
 
At least onceってぶっちゃけ問題の先送りだったよね #kafkajp
At least onceってぶっちゃけ問題の先送りだったよね #kafkajpAt least onceってぶっちゃけ問題の先送りだったよね #kafkajp
At least onceってぶっちゃけ問題の先送りだったよね #kafkajp
 
オススメのJavaログ管理手法 ~コンテナ編~(Open Source Conference 2022 Online/Spring 発表資料)
オススメのJavaログ管理手法 ~コンテナ編~(Open Source Conference 2022 Online/Spring 発表資料)オススメのJavaログ管理手法 ~コンテナ編~(Open Source Conference 2022 Online/Spring 発表資料)
オススメのJavaログ管理手法 ~コンテナ編~(Open Source Conference 2022 Online/Spring 発表資料)
 
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
 

Similar to Spring fest2020 spring-security

Similar to Spring fest2020 spring-security (7)

Spring Framework ふりかえりと4.3新機能
Spring Framework ふりかえりと4.3新機能Spring Framework ふりかえりと4.3新機能
Spring Framework ふりかえりと4.3新機能
 
Rails4 security
Rails4 securityRails4 security
Rails4 security
 
Scala 初心者向けlt
Scala 初心者向けltScala 初心者向けlt
Scala 初心者向けlt
 
ゼロトラスト三銃士〜Okta x Jamf x Netskopeネタ10連発〜
ゼロトラスト三銃士〜Okta x Jamf x Netskopeネタ10連発〜ゼロトラスト三銃士〜Okta x Jamf x Netskopeネタ10連発〜
ゼロトラスト三銃士〜Okta x Jamf x Netskopeネタ10連発〜
 
WordPressとリスク管理 at 第42回 WordBench大阪
WordPressとリスク管理 at 第42回 WordBench大阪WordPressとリスク管理 at 第42回 WordBench大阪
WordPressとリスク管理 at 第42回 WordBench大阪
 
FuelPHP Osu Nagoya vol.1
FuelPHP Osu Nagoya vol.1FuelPHP Osu Nagoya vol.1
FuelPHP Osu Nagoya vol.1
 
Cloud Foundry にアプリケーションを push する際の典型的な10のエラー
Cloud Foundry にアプリケーションを push する際の典型的な10のエラーCloud Foundry にアプリケーションを push する際の典型的な10のエラー
Cloud Foundry にアプリケーションを push する際の典型的な10のエラー
 

More from 土岐 孝平

試験にでるSpring
試験にでるSpring試験にでるSpring
試験にでるSpring
土岐 孝平
 

More from 土岐 孝平 (12)

What's new in Spring Boot 2.6 ?
What's new in Spring Boot 2.6 ?What's new in Spring Boot 2.6 ?
What's new in Spring Boot 2.6 ?
 
SpringベースのCloud Native Application
SpringベースのCloud Native ApplicationSpringベースのCloud Native Application
SpringベースのCloud Native Application
 
Microserviceの今どきのインフラを探る
Microserviceの今どきのインフラを探るMicroserviceの今どきのインフラを探る
Microserviceの今どきのインフラを探る
 
OpenID Connect入門
OpenID Connect入門OpenID Connect入門
OpenID Connect入門
 
入社1年目のプログラミング初心者がSpringを学ぶための手引き
入社1年目のプログラミング初心者がSpringを学ぶための手引き入社1年目のプログラミング初心者がSpringを学ぶための手引き
入社1年目のプログラミング初心者がSpringを学ぶための手引き
 
これから始めるSpringのwebアプリケーション
これから始めるSpringのwebアプリケーションこれから始めるSpringのwebアプリケーション
これから始めるSpringのwebアプリケーション
 
今さら聞けないDiとspring
今さら聞けないDiとspring今さら聞けないDiとspring
今さら聞けないDiとspring
 
Springを使ったwebアプリにリファクタリングしよう
Springを使ったwebアプリにリファクタリングしようSpringを使ったwebアプリにリファクタリングしよう
Springを使ったwebアプリにリファクタリングしよう
 
業務システムとマイクロサービス
業務システムとマイクロサービス業務システムとマイクロサービス
業務システムとマイクロサービス
 
エッセンシャルCore springハンズオン
エッセンシャルCore springハンズオンエッセンシャルCore springハンズオン
エッセンシャルCore springハンズオン
 
試験にでるSpring
試験にでるSpring試験にでるSpring
試験にでるSpring
 
vFabricを触ろう
vFabricを触ろうvFabricを触ろう
vFabricを触ろう
 

Spring fest2020 spring-security

  • 2. 自己紹介 • 土岐 孝平 • 合同会社 現場指向 • Webアプリ「メモラキー」の運営 • システム開発の支援 • 研修の講師 • 書籍の執筆 2 [改訂新版]Spring入門https://www.memorarchy.com
  • 4. 本セッションの目的 • Spring Securityが裏で何をやっているかを知って、 問題が起きたときのデバッグや、カスタマイズ方法 の調査を円滑にする • キーとなる以下の2つを抑える – Security Filter Chain – Security Context 4 網羅的な機能の説明や、設定ノウハウの説明は行いません
  • 5. Security Filter Chainとは? • Spring Securityが提供するFilter※の繋がり • Servlet Filterの仕組みを使って処理を挟み込む • 各Filterは、認証、URLパスの認可、CSRF防止などの役割 を持つ 5 ※ 個々のFilterは ServletのFilterイン タフェースを実装し ているが、Servletコ ンテナに登録されて いる訳ではない Filter1 FilterX DispatcherServlet Delegating FilterProxy ブラウザ ・・ ・ ・・・ Controller ・・ ・ ServletのFilter Chain ★Security Filter Chain Filter2 Spring MVCのサーブ レット
  • 6. 主なFilter 6 クラス名 役割 CsrfFilter CSRFトークンの発行やチェックを行う HeaderWriterFilter セキュリティ関連のレスポンスヘッダを 設定する BasicAuthenticationFilter Basic認証を行う UsernamePasswordAuthenticationFilter フォーム認証を行う ExceptionTranslationFilter 後続の処理で発生した認証・認可の例 外をキャッチしてハンドリング(エラー画 面に遷移など)する FilterSecurityInterceptor URLのパスの認可を行う SecurityContextPersistenceFilter 「Security Context」を用意して、HTTP セッションやThreadLocalに格納する 次ページで説明
  • 7. Security Context • 認証したユーザ情報(IDや権限など)を格納するオブジェクト • HTTPセッションに保持されるため、リクエストを跨ってユー ザ情報を参照できる • ThreadLocal(スレッド毎にデータを管理してくれる)にも保持 されるため、リクエスト(スレッド)の処理内の任意のタイミング でユーザ情報を参照可能 – Controllerの引数で受けとる – 画面にユーザ情報を表示するときに参照 – staticメソッドでプログラムの任意の箇所で参照 • SecurityContextHolder.getContext() – 認可時(URLのパス、メソッド、画面内の表示非表示)に参照 7
  • 9. Security Filter Chainの作成 • WebSecurityConfigurerAdapter を継承して @EnableWebSecurityを付けたJavaConfigのクラス (@Configurationを付けたクラス)を作成する • @EnableWebSecurityがインポートしている WebSecurityConfigurationクラスの中で、Security Filter Chainのオブジェクトが作成される • 標準的なFilterが自動で登録されるので、メソッドをオーバー ライドして個別の設定を行う 9 @Configuration@Configuration @EnableWebSecurity public class SampleSecurityConfig extends WebSecurityConfigurerAdapter { }
  • 10. 個別の設定のサンプル 10 @Configuration @EnableWebSecurity public class SampleSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .mvcMatchers("/admin/**").hasAuthority("ADMIN") .anyRequest().authenticated().and() .httpBasic(); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder(); auth .inMemoryAuthentication() .withUser("foo").password(encoder.encode("passfoo")).authorities("ADMIN").and() .withUser("bar").password(encoder.encode("passbar")).authorities("USER"); } } 「/admin」 で始まるパスは「ADMIN」権限が 必要、それ以外は認証されてればOK Basic認証を有効にする 「foo」ユーザは「ADMIN」権限、「bar」ユーザは 「USER」権限という認証情報をメモリ上に保管
  • 11. 出来上がった主なオブジェクト 11 Authentication Manager UserDetailsService AccessDecision Manager Dispatcher Servlet Delegating FilterProxy ブラウザ ・・ ・ ・・ ・ Controller ServletのFilter Chain ★Security Filter Chain ID・パスワードのチェックを 行う。認証情報は UserDetailsServieから取得 権限のチェックを行う 認証情報を取得。今回はメ モリ上から取得 URLのパスの認可を行う BasicAuthenticationFilter ExceptionTranslationFilter SecurityContextPersistenceFilter FilterSecurityInterceptor Basic認証を行う
  • 12. Security Filter Chainの動作イメージ • 認可が必要なURLに初回アクセスしたとき – ※主なFilterに絞っています 12 BasicAuthenticationFilter ExceptionTranslationFilter SecurityContextPersistenceFilter FilterSecurityInterceptor DispatcherServlet リクエスト(/admin/foo) レスポンス HTTPセッションにSecurity Context がないため、新しく用意する。 用意したSecurity Contextを、 ThreadLocalに入れる Authorization ID Context AuthorizationヘッダからユーザID・ パスワードを取得して認証する。 OKならユーザ情報をSecurity Contextに入れる スルー URLパスに設定された権限と、 Security Contextのユーザ情報の権 限を比較する。OKなら後続の処理 を呼び出す スルー 例外が投げられた訳 ではないのでスルー スルー ユーザ情報入りの Security ContextをHTTP セッションに入れる
  • 13. フォーム認証のサンプル 13 @Configuration @EnableWebSecurity public class SampleSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .mvcMatchers("/admin/**").hasAuthority("ADMIN") .anyRequest().authenticated().and() .formLogin() .loginPage("/login").permitAll() .loginProcessingUrl("/login") .usernameParameter("username").passwordParameter("password") .failureUrl("/login?error"); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { ・・・ 省略 } } フォーム認証を有効にする ログイン画面のパス。未認証のユーザ を自動的に遷移させる 認証リクエストのパス。POST前提 認証リクエストに乗せるユーザIDとパス ワードのパラメータ名ログイン失敗時に遷移 するパス
  • 14. ログイン画面のサンプル 14 <!DOCTYPE HTML> <html xmlns:th="http://www.thymeleaf.org"> <body> <form th:action="@{/login}" method="post"> <input type="text" name="username" /> <input type="text" name="password" /> <input type="submit" value="送信" /> </form> </body> </html> POSTメソッドを指定 ※テンプレートエンジンのThymeleafを使用
  • 15. Security Filter Chainの動作イメージ1/3 • 未認証のユーザが、認可が必要なURLにアクセス 15 UsernamePasswordAuthenticationFilter ExceptionTranslationFilter SecurityContextPersistenceFilter FilterSecurityInterceptor DispatcherServlet ログイン画面にリダイレクトHTTPセッションにSecurity Context がないため、新しく用意する。 用意したSecurity Contextを、 ThreadLocalに入れる 認証のリクエストでは無いので スルー リクエスト(/admin/foo) スルー 未認証なので、 AccessDeniedExceptionをスロー AccessDeniedExceptionをキャッチ して、ログイン画面にリダイレクト するレスポンスを設定。その際、 リクエストの内容をHTTPセッショ ンに格納する(ログイン後に自動 で遷移するため) スルー 空のSecurity Contextを HTTPセッションに入れる。
  • 16. Security Filter Chainの動作イメージ2/3 • 認証リクエストを送信 16 UsernamePasswordAuthenticationFilter ExceptionTranslationFilter SecurityContextPersistenceFilter FilterSecurityInterceptor /admin/fooにリダイレクトリクエスト(POSTの/login) HTTPセッションから空のSecurity Contextを取得して、ThreadLocal に入れる。 認証リクエストだと判断して、リク エストパラメータのID・パスワード で認証する。認証したユーザ情 報をSecurity Contextに入れる。 HTTPセッションに格納しておいた リクエストにリダイレクトするレス ポンスを設定。 DispatcherServlet ユーザ情報が入った Security ContextをHTTP セッションに入れる。
  • 17. Security Filter Chainの動作イメージ3/3 • /admin/fooにアクセス 17 SecurityContextPersistenceFilter FilterSecurityInterceptor レスポンスリクエスト(/admin/foo) HTTPセッションからSecurity Context(ユーザ情報入り)を取得 して、ThreadLocalに入れる。 DispatcherServlet ユーザ情報が入った Security ContextをHTTP セッションに入れる。 UsernamePasswordAuthenticationFilter ExceptionTranslationFilter 認証のリクエストでは無いので スルー スルー URLパスに設定された権限と、 Security Contextのユーザ情報の 権限を比較する。OKなら後続の処 理を呼び出す スルー 例外が投げられた訳 ではないのでスルー スルー
  • 18. Security Filter Chainのログ 1/2 • どのFilterが、どの順番で動いたかをログに出力す ることが可能 – デバッグに便利 • 設定方法 – ロガーの「org.springframework.security」をDEBUGレベルに する – application.propertiesでの設定例 18 logging.level.org.springframework.security=DEBUG
  • 19. Security Filter Chainのログ 2/2 • 出力例 – 未認証のユーザが、認可が必要なURLにアクセスしたと きのログ(抜粋) 19 /admin/foo at position 1 of 12 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter' /admin/foo at position 2 of 12 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter' No HttpSession currently exists No SecurityContext was available from the HttpSession: null. A new one will be created. /admin/foo at position 3 of 12 in additional filter chain; firing Filter: 'HeaderWriterFilter' /admin/foo at position 4 of 12 in additional filter chain; firing Filter: 'CsrfFilter' /admin/foo at position 5 of 12 in additional filter chain; firing Filter: 'LogoutFilter' Request 'GET /admin/foo' doesn't match 'POST /logout' /admin/foo at position 6 of 12 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter' Request 'GET /admin/foo' doesn't match 'POST /login' /admin/foo at position 7 of 12 in additional filter chain; firing Filter: 'RequestCacheAwareFilter' saved request doesn't match /admin/foo at position 8 of 12 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter' /admin/foo at position 9 of 12 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter' /admin/foo at position 10 of 12 in additional filter chain; firing Filter: 'SessionManagementFilter' /admin/foo at position 11 of 12 in additional filter chain; firing Filter: 'ExceptionTranslationFilter' /admin/foo at position 12 of 12 in additional filter chain; firing Filter: 'FilterSecurityInterceptor' Secure object: FilterInvocation: URL: /admin/foo; Attributes: [hasAuthority('ADMIN')] Voter: org.springframework.security.web.access.expression.WebExpressionVoter@7d30e6, returned: -1 o.s.s.w.a.ExceptionTranslationFilter : Access is denied (user is anonymous); redirecting to authentication entry point Filterの数と処理 準が表示われる 特別な処理が行われた らログにでる
  • 20. さいごに • Spring Securityの裏の動きのイメージが沸いて、デ バッグやカスタマイズの作業がし易くなれば幸いで す。 • おすすめのサイト – Spring Securityのマニュアルの「The Big Picture」の章 • https://docs.spring.io/spring- security/site/docs/current/reference/html5/#servlet- architecture 20