最新の安定バージョンについては、Spring Security 6.3.1 を使用してください!

サーブレット認証アーキテクチャ

この説明では、サーブレットのセキュリティ: 全体像を拡張して、サーブレット認証で使用される Spring Security の主要なアーキテクチャコンポーネントについて説明します。これらの部品がどのように組み合わされるかを説明する具体的なフローが必要な場合は、認証メカニズム固有のセクションを参照してください。

SecurityContextHolder

Spring Security の認証モデルの中核は SecurityContextHolder です。SecurityContext が含まれています。

securitycontextholder

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

GrantedAuthoritys (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 で認証が失敗します。

providermanager

実際には、各 AuthenticationProvider は特定の型の認証を実行する方法を知っています。例: ある AuthenticationProvider はユーザー名 / パスワードを検証でき、別の AuthenticationProvider は SAML アサーションを認証できる可能性があります。これにより、各 AuthenticationProvider は非常に特殊な型の認証を行うことができますが、複数の型の認証をサポートし、単一の AuthenticationManager Bean のみを公開します。

ProviderManager では、AuthenticationProvider が認証を実行できない場合に参照されるオプションの親 AuthenticationManager を構成することもできます。親はどの型の AuthenticationManager でもかまいませんが、しばしば ProviderManager のインスタンスです。

providermanager parent

実際、複数の ProviderManager インスタンスが同じ親 AuthenticationManager を共有する場合があります。これは、認証が共通する複数の SecurityFilterChain インスタンス(共有親 AuthenticationManager)が存在するシナリオでは多少一般的ですが、異なる認証メカニズム(異なる ProviderManager インスタンス)もあります。

providermanagers parent

デフォルトでは、ProviderManager は、成功した認証リクエストによって返される Authentication オブジェクトから機密資格情報をクリアしようとします。これにより、HttpSession でパスワードなどの情報が必要以上に長く保持されなくなります。

これにより、たとえば、ステートレスアプリケーションのパフォーマンスを向上させるために、ユーザーオブジェクトのキャッシュを使用している場合に問題が発生する可能性があります。Authentication にキャッシュ内のオブジェクト(UserDetails インスタンスなど)への参照が含まれ、その資格情報が削除されている場合、キャッシュされた値に対して認証することはできなくなります。キャッシュを使用している場合は、これを考慮する必要があります。明らかな解決策は、キャッシュ実装または返された Authentication オブジェクトを作成する AuthenticationProvider のいずれかで、最初にオブジェクトのコピーを作成することです。または、ProviderManager の eraseCredentialsAfterAuthentication プロパティを無効にすることができます。詳細については、Javadoc を参照してください。

AuthenticationProvider

複数の AuthenticationProviders (Javadoc) ProviderManager に注入できます。各 AuthenticationProvider は特定の型の認証を実行します。例: DaoAuthenticationProvider はユーザー名 / パスワードベースの認証をサポートし、JwtAuthenticationProvider は JWT トークンの認証をサポートします。

AuthenticationEntryPoint を使用した資格情報のリクエスト

AuthenticationEntryPoint (Javadoc) は、クライアントから資格情報をリクエストする HTTP レスポンスを送信するために使用されます。

クライアントは、リソースをリクエストするためにユーザー名 / パスワードなどの資格情報を積極的に含めることがあります。これらの場合、Spring Security はすでに含まれているため、クライアントから資格情報をリクエストする HTTP レスポンスを提供する必要はありません。

その他の場合、クライアントは、アクセスが認可されていないリソースに対して認証されていないリクエストを行います。この場合、AuthenticationEntryPoint の実装を使用して、クライアントに資格情報をリクエストします。AuthenticationEntryPoint 実装は、ログインページへのリダイレクトを実行したり、WWW 認証ヘッダーで応答したりする場合があります。

AbstractAuthenticationProcessingFilter

AbstractAuthenticationProcessingFilter (Javadoc) は、ユーザーの資格情報を認証するためのベース Filter として使用されます。資格情報を認証する前に、Spring Security は通常 AuthenticationEntryPoint を使用して資格情報をリクエストします。

次に、AbstractAuthenticationProcessingFilter は送信された認証リクエストを認証できます。

abstractauthenticationprocessingfilter

number 1 ユーザーが資格情報を送信すると、AbstractAuthenticationProcessingFilter は認証される HttpServletRequest から Authentication を作成します。作成される Authentication の型は、AbstractAuthenticationProcessingFilter のサブクラスによって異なります。例: UsernamePasswordAuthenticationFilter は、HttpServletRequest で送信されたユーザー名パスワードから UsernamePasswordAuthenticationToken を作成します。

number 2 次に、AuthenticationAuthenticationManager に渡されて認証されます。

number 3 認証に失敗した場合、Failure

  • SecurityContextHolder はクリアされます。

  • RememberMeServices.loginFail が呼び出されます。設定されていないことを覚えていれば、これはノーオペレーションです。

  • AuthenticationFailureHandler が呼び出されます。

number 4 認証が成功した場合は、Success .

  • SessionAuthenticationStrategy に新しいログインが通知されます。

  • 認証SecurityContextHolder に設定されます。その後、SecurityContextPersistenceFilter は SecurityContext を HttpSession に保存します。

  • RememberMeServices.loginSuccess が呼び出されます。設定されていないことを覚えていれば、これはノーオペレーションです。

  • ApplicationEventPublisher は InteractiveAuthenticationSuccessEvent を公開します。

  • AuthenticationSuccessHandler が呼び出されます。