最新の安定バージョンについては、Spring Security 6.4.2 を使用してください! |
サーブレット認証アーキテクチャ
この説明では、サーブレットのセキュリティ: 全体像を拡張して、サーブレット認証で使用される Spring Security の主要なアーキテクチャコンポーネントについて説明します。これらの部品がどのように組み合わされるかを説明する具体的なフローが必要な場合は、認証メカニズム固有のセクションを参照してください。
SecurityContextHolder -
SecurityContextHolder
は、Spring Security が認証されたユーザーの詳細を格納する場所です。SecurityContext -
SecurityContextHolder
から取得され、現在認証されているユーザーのAuthentication
が含まれています。認証 -
AuthenticationManager
への入力として、ユーザーが認証のために提供した資格情報、またはSecurityContext
からの現在のユーザーを提供できます。GrantedAuthority -
Authentication
のプリンシパルに付与される権限 (すなわち、ロール、スコープなど。)AuthenticationManager - Spring Security のフィルターが認証を実行する方法を定義する API。
ProviderManager -
AuthenticationManager
の最も一般的な実装。AuthenticationProvider -
ProviderManager
が特定の型の認証を実行するために使用します。AuthenticationEntryPoint
を使用した資格情報のリクエスト - クライアントから資格情報をリクエストするために使用 (つまり、ログインページへのリダイレクト、WWW-Authenticate
レスポンスの送信など。)AbstractAuthenticationProcessingFilter - 認証に使用されるベース
Filter
。また、これにより、認証の高レベルのフローと各部分がどのように連携するかについての良いアイデアが得られます。
SecurityContextHolder
Spring Security の認証モデルの中核は SecurityContextHolder
です。SecurityContext が含まれています。
SecurityContextHolder
は、Spring Security が認証されたユーザーの詳細を格納する場所です。Spring Security は、SecurityContextHolder
がどのように設定されているかを気にしません。値が含まれている場合は、現在認証されているユーザーとして使用されます。
ユーザーが認証されていることを示す最も簡単な方法は、SecurityContextHolder
を直接設定することです。
SecurityContextHolder
の設定 Java
Kotlin
SecurityContext context = SecurityContextHolder.createEmptyContext(); (1)
Authentication authentication =
new TestingAuthenticationToken("username", "password", "ROLE_USER"); (2)
context.setAuthentication(authentication);
SecurityContextHolder.setContext(context); (3)
val context: SecurityContext = SecurityContextHolder.createEmptyContext() (1)
val authentication: Authentication = TestingAuthenticationToken("username", "password", "ROLE_USER") (2)
context.authentication = authentication
SecurityContextHolder.setContext(context) (3)
1 | 空の SecurityContext を作成することから始めます。SecurityContextHolder.getContext().setAuthentication(authentication) を使用する代わりに新しい SecurityContext インスタンスを作成して、複数のスレッド間で競合状態を回避することが重要です。 |
2 | 次に、新しい Authentication オブジェクトを作成します。Spring Security は、どの型の Authentication 実装が SecurityContext に設定されているかを気にしません。ここでは、非常に単純であるため、TestingAuthenticationToken を使用しています。より一般的な本番シナリオは UsernamePasswordAuthenticationToken(userDetails, password, authorities) です。 |
3 | 最後に、SecurityContextHolder に SecurityContext を設定します。Spring Security は、この情報を認証に使用します。 |
認証されたプリンシパルに関する情報を取得する場合は、SecurityContextHolder
にアクセスして取得できます。
Java
Kotlin
SecurityContext context = SecurityContextHolder.getContext();
Authentication authentication = context.getAuthentication();
String username = authentication.getName();
Object principal = authentication.getPrincipal();
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
val context = SecurityContextHolder.getContext()
val authentication = context.authentication
val username = authentication.name
val principal = authentication.principal
val authorities = authentication.authorities
デフォルトでは、SecurityContextHolder
は ThreadLocal
を使用してこれらの詳細を格納します。つまり、SecurityContext
が明示的にそれらのメソッドへの引数として渡されない場合でも、SecurityContext
は同じスレッド内のメソッドで常に使用可能です。現在のプリンシパルのリクエストが処理された後にスレッドをクリアするように注意を払えば、ThreadLocal
をこのように使用することは非常に安全です。Spring Security の FilterChainProxy により、SecurityContext
は常にクリアされます。
一部のアプリケーションは、スレッドを操作する特定の方法のため、ThreadLocal
の使用に完全には適していません。例: Swing クライアントは、Java 仮想マシンのすべてのスレッドが同じセキュリティコンテキストを使用することを望む場合があります。SecurityContextHolder
は、起動時の戦略を使用して構成し、コンテキストの保存方法を指定できます。スタンドアロンアプリケーションの場合は、SecurityContextHolder.MODE_GLOBAL
戦略を使用します。他のアプリケーションでも、セキュアスレッドによって生成されたスレッドに同じセキュリティ ID を想定させたい場合があります。これは、SecurityContextHolder.MODE_INHERITABLETHREADLOCAL
を使用して実現されます。モードは、デフォルトの SecurityContextHolder.MODE_THREADLOCAL
から 2 つの方法で変更できます。1 つはシステムプロパティを設定すること、もう 1 つは SecurityContextHolder
で静的メソッドを呼び出すことです。ほとんどのアプリケーションはデフォルトから変更する必要はありませんが、変更する場合は、Javadoc for SecurityContextHolder
を参照して詳細を確認してください。
SecurityContext
SecurityContext
(Javadoc) は SecurityContextHolder から取得されます。SecurityContext
には認証オブジェクトが含まれています。
認証
Authentication
(Javadoc) は、Spring Security 内で 2 つの主な目的を果たします。
ユーザーが認証のために提供した資格情報を提供する
AuthenticationManager
への入力。このシナリオで使用すると、isAuthenticated()
はfalse
を返します。現在認証されているユーザーを表します。現在の
Authentication
は SecurityContext から取得できます。
Authentication
には以下が含まれます。
principal
- ユーザーを識別します。ユーザー名 / パスワードで認証する場合、これは多くの場合UserDetails
のインスタンスです。credentials
- 多くの場合、パスワード。多くの場合、これはユーザーが認証された後にクリアされ、リークされないようにします。authorities
-GrantedAuthority
は、ユーザーに付与される高レベルのアクセス許可です。いくつかの例は、ロールまたはスコープです。
GrantedAuthority
GrantedAuthority
s (Javadoc) は、ユーザーに付与される高レベルのアクセス許可です。いくつかの例は、ロールまたはスコープです。
GrantedAuthority
は、Authentication.getAuthorities()
メソッドから取得できます。このメソッドは、GrantedAuthority
オブジェクトの Collection
を提供します。GrantedAuthority
は、当然のことながら、プリンシパルに付与される権限です。このような権限は通常、ROLE_ADMINISTRATOR
や ROLE_HR_SUPERVISOR
などの「ロール」です。これらのロールは、後で Web 認可、メソッド認可、ドメインオブジェクト認可用に構成されます。Spring Security の他の部分は、これらの権限を解釈でき、それらが存在することを期待しています。ユーザー名 / パスワードベースの認証を使用する場合、GrantedAuthority
は通常 UserDetailsService
によってロードされます。
通常、GrantedAuthority
オブジェクトはアプリケーション全体の権限です。特定のドメインオブジェクトに固有ではありません。Employee
オブジェクト番号 54 へのアクセス許可を表す GrantedAuthority
を持っている可能性は低いでしょう。なぜなら、そのような権限が何千もあると、すぐにメモリ不足になるからです(または、少なくとも、アプリケーションに時間がかかるからです)。ユーザーを認証する時間)。もちろん、Spring Security はこの一般的な要件を処理するように明示的に設計されていますが、代わりにプロジェクトのドメインオブジェクトセキュリティ機能をこの目的に使用します。
AuthenticationManager
AuthenticationManager
は、Spring Security のフィルターが認証を実行する方法を定義する API です。返された Authentication
は、AuthenticationManager
を呼び出したコントローラー(つまり、Spring Security の Filters
)によって SecurityContextHolder に設定されます。Spring Security の Filters
と統合していない場合は、SecurityContextHolder
を直接設定でき、AuthenticationManager
を使用する必要はありません。
AuthenticationManager
の実装は何でもかまいませんが、最も一般的な実装は ProviderManager
です。
ProviderManager
ProviderManager
(Javadoc) は、AuthenticationManager
の最も一般的に使用される実装です。ProviderManager
は AuthenticationProvider
の List
に委譲します。各 AuthenticationProvider
には、認証が成功するか、失敗するか、決定を下せず、ダウンストリーム AuthenticationProvider
が決定できるようにするかを示す機会があります。構成された AuthenticationProvider
のいずれも認証できない場合、ProviderManager
が渡された Authentication
の型をサポートするように構成されていないことを示す特別な AuthenticationException
である ProviderNotFoundException
で認証が失敗します。
実際には、各 AuthenticationProvider
は特定の型の認証を実行する方法を知っています。例: ある AuthenticationProvider
はユーザー名 / パスワードを検証でき、別の AuthenticationProvider
は SAML アサーションを認証できる可能性があります。これにより、各 AuthenticationProvider
は非常に特殊な型の認証を行うことができますが、複数の型の認証をサポートし、単一の AuthenticationManager
Bean のみを公開します。
ProviderManager
では、AuthenticationProvider
が認証を実行できない場合に参照されるオプションの親 AuthenticationManager
を構成することもできます。親はどの型の AuthenticationManager
でもかまいませんが、しばしば ProviderManager
のインスタンスです。
実際、複数の ProviderManager
インスタンスが同じ親 AuthenticationManager
を共有する場合があります。これは、認証が共通する複数の SecurityFilterChain
インスタンス(共有親 AuthenticationManager
)が存在するシナリオでは多少一般的ですが、異なる認証メカニズム(異なる ProviderManager
インスタンス)もあります。
デフォルトでは、ProviderManager
は、成功した認証リクエストによって返される Authentication
オブジェクトから機密資格情報をクリアしようとします。これにより、HttpSession
でパスワードなどの情報が必要以上に長く保持されなくなります。
これにより、たとえば、ステートレスアプリケーションのパフォーマンスを向上させるために、ユーザーオブジェクトのキャッシュを使用している場合に問題が発生する可能性があります。Authentication
にキャッシュ内のオブジェクト(UserDetails
インスタンスなど)への参照が含まれ、その資格情報が削除されている場合、キャッシュされた値に対して認証することはできなくなります。キャッシュを使用している場合は、これを考慮する必要があります。明らかな解決策は、キャッシュ実装または返された Authentication
オブジェクトを作成する AuthenticationProvider
のいずれかで、最初にオブジェクトのコピーを作成することです。または、ProviderManager
の eraseCredentialsAfterAuthentication
プロパティを無効にすることができます。詳細については、Javadoc を参照してください。
AuthenticationProvider
複数の AuthenticationProvider
s (Javadoc) を ProviderManager
に注入できます。各 AuthenticationProvider
は特定の型の認証を実行します。例: DaoAuthenticationProvider
はユーザー名 / パスワードベースの認証をサポートし、JwtAuthenticationProvider
は JWT トークンの認証をサポートします。
AuthenticationEntryPoint
を使用した資格情報のリクエスト
AuthenticationEntryPoint
(Javadoc) は、クライアントから資格情報をリクエストする HTTP レスポンスを送信するために使用されます。
クライアントは、リソースをリクエストするためにユーザー名 / パスワードなどの資格情報を積極的に含めることがあります。これらの場合、Spring Security はすでに含まれているため、クライアントから資格情報をリクエストする HTTP レスポンスを提供する必要はありません。
AbstractAuthenticationProcessingFilter
AbstractAuthenticationProcessingFilter
(Javadoc) は、ユーザーの資格情報を認証するためのベース Filter
として使用されます。資格情報を認証する前に、Spring Security は通常 AuthenticationEntryPoint
を使用して資格情報をリクエストします。
次に、AbstractAuthenticationProcessingFilter
は送信された認証リクエストを認証できます。
ユーザーが資格情報を送信すると、AbstractAuthenticationProcessingFilter
は認証される HttpServletRequest
から Authentication
を作成します。作成される Authentication
の型は、AbstractAuthenticationProcessingFilter
のサブクラスによって異なります。例: UsernamePasswordAuthenticationFilter
は、HttpServletRequest
で送信されたユーザー名とパスワードから UsernamePasswordAuthenticationToken
を作成します。
次に、Authentication
が AuthenticationManager
に渡されて認証されます。
認証に失敗した場合、Failure
SecurityContextHolder はクリアされます。
RememberMeServices.loginFail
が呼び出されます。設定されていないことを覚えていれば、これはノーオペレーションです。AuthenticationFailureHandler
が呼び出されます。
認証が成功した場合は、Success .
SessionAuthenticationStrategy
に新しいログインが通知されます。認証は SecurityContextHolder に設定されます。その後、
SecurityContextPersistenceFilter
はSecurityContext
をHttpSession
に保存します。RememberMeServices.loginSuccess
が呼び出されます。設定されていないことを覚えていれば、これはノーオペレーションです。ApplicationEventPublisher
はInteractiveAuthenticationSuccessEvent
を公開します。AuthenticationSuccessHandler
が呼び出されます。