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

匿名認証

概要

一般に、許可するものと明示的に禁止するものを明示的に指定する「デフォルトで拒否」を採用することは、優れたセキュリティ慣行と考えられています。特に Web アプリケーションの場合、認証されていないユーザーがアクセスできるものを定義することも同様の状況です。多くのサイトでは、いくつかの URL 以外(ホームページやログインページなど)についてユーザーを認証する必要があります。この場合、すべての保護されたリソースに対してではなく、これらの特定の URL に対してアクセス構成属性を定義するのが最も簡単です。別の言い方をすると、ROLE_SOMETHING がデフォルトで必要であり、アプリケーションのログイン、ログアウト、ホームページなど、このルールの特定の例外のみを許可すると言うのはいいことです。これらのページをフィルターチェーンから完全に省略して、アクセス制御チェックをバイパスすることもできますが、他の理由、特に認証されたユーザーに対してページの動作が異なる場合、これは望ましくない場合があります。

これが匿名認証の意味です。「匿名で認証された」ユーザーと認証されていないユーザーの間に実際の概念上の違いはないことに注意してください。Spring Security の匿名認証は、アクセス制御属性を構成するためのより便利な方法を提供します。たとえば、getCallerPrincipal などのサーブレット API を呼び出すと、SecurityContextHolder に実際には匿名の認証オブジェクトが存在する場合でも、null が返されます。

監査インターセプターが SecurityContextHolder を照会して、特定の操作を担当したプリンシパルを識別する場合など、匿名認証が役立つ状況が他にもあります。SecurityContextHolder が常に Authentication オブジェクトを含み、決して null を含まないことがわかっている場合、クラスをより堅牢に作成できます。

構成

匿名認証のサポートは、HTTP 構成 Spring Security 3.0 を使用すると自動的に提供され、<anonymous> 要素を使用してカスタマイズ(または無効化)できます。従来の Bean 構成を使用していない限り、ここで説明する Bean を構成する必要はありません。

匿名認証機能を一緒に提供する 3 つのクラス。AnonymousAuthenticationToken は Authentication の実装であり、匿名プリンシパルに適用される GrantedAuthority を格納します。AnonymousAuthenticationToken が受け入れられるように、ProviderManager にチェーンされた対応する AnonymousAuthenticationProvider があります。最後に、AnonymousAuthenticationFilter があります。これは、通常の認証メカニズムの後にチェーンされ、既存の Authentication が保持されていない場合、AnonymousAuthenticationToken を SecurityContextHolder に自動的に追加します。フィルターと認証プロバイダーの定義は次のように表示されます。

<bean id="anonymousAuthFilter"
	class="org.springframework.security.web.authentication.AnonymousAuthenticationFilter">
<property name="key" value="foobar"/>
<property name="userAttribute" value="anonymousUser,ROLE_ANONYMOUS"/>
</bean>

<bean id="anonymousAuthenticationProvider"
	class="org.springframework.security.authentication.AnonymousAuthenticationProvider">
<property name="key" value="foobar"/>
</bean>

key はフィルターと認証プロバイダーの間で共有されるため、前者によって作成されたトークンは後者 [ 1 ] によって受け入れられます。userAttribute は usernameInTheAuthenticationToken,grantedAuthority[,grantedAuthority] の形式で表現されます。これは、InMemoryDaoImpl の userMap プロパティの等号の後に使用されるものと同じ構文です。

前に説明したように、匿名認証の利点は、すべての URI パターンにセキュリティを適用できることです。例:

<bean id="filterSecurityInterceptor"
	class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="accessDecisionManager" ref="httpRequestAccessDecisionManager"/>
<property name="securityMetadata">
	<security:filter-security-metadata-source>
	<security:intercept-url pattern='/index.jsp' access='ROLE_ANONYMOUS,ROLE_USER'/>
	<security:intercept-url pattern='/hello.htm' access='ROLE_ANONYMOUS,ROLE_USER'/>
	<security:intercept-url pattern='/logoff.jsp' access='ROLE_ANONYMOUS,ROLE_USER'/>
	<security:intercept-url pattern='/login.jsp' access='ROLE_ANONYMOUS,ROLE_USER'/>
	<security:intercept-url pattern='/**' access='ROLE_USER'/>
	</security:filter-security-metadata-source>" +
</property>
</bean>

AuthenticationTrustResolver

匿名認証の議論を締めくくるのは、AuthenticationTrustResolver インターフェースとそれに対応する AuthenticationTrustResolverImpl 実装です。このインターフェースは isAnonymous(Authentication) メソッドを提供します。これにより、関心のあるクラスはこの特別な型の認証ステータスを考慮することができます。ExceptionTranslationFilter は、AccessDeniedException の処理にこのインターフェースを使用します。AccessDeniedException がスローされ、認証が匿名型の場合、403(禁止)レスポンスをスローする代わりに、フィルターは代わりに AuthenticationEntryPoint を開始し、プリンシパルが正しく認証できるようにします。これは必要な区別です。そうでなければ、プリンシパルは常に「認証済み」とみなされ、フォーム、基本、ダイジェスト、その他の通常の認証メカニズムを介してログインする機会が与えられません。

上記のインターセプター構成の ROLE_ANONYMOUS 属性が IS_AUTHENTICATED_ANONYMOUSLY に置き換えられていることがよくあります。これは、アクセス制御を定義する場合と実質的に同じです。これは、認証の章で説明する AuthenticatedVoter の使用例です。AuthenticationTrustResolver を使用して、この特定の構成属性を処理し、匿名ユーザーにアクセスを認可します。AuthenticatedVoter アプローチは、匿名、remember-me、完全に認証されたユーザーを区別できるため、より強力です。ただし、この機能が必要ない場合は、ROLE_ANONYMOUS を使用できます。これは、Spring Security の標準 RoleVoter によって処理されます。

Spring MVC を使用した匿名認証の取得

独自の引数リゾルバーを使用する Spring MVC は、型 Principal のパラメーターを解決します

これは、次のような構成を意味します。

  • Java

  • Kotlin

@GetMapping("/")
public String method(Authentication authentication) {
	if (authentication instanceof AnonymousAuthenticationToken) {
		return "anonymous";
	} else {
		return "not anonymous";
	}
}
@GetMapping("/")
fun method(authentication: Authentication?): String {
    return if (authentication is AnonymousAuthenticationToken) {
        "anonymous"
    } else {
        "not anonymous"
    }
}

匿名のリクエストであっても、常に「匿名ではない」を返します。その理由は、Spring MVC が HttpServletRequest#getPrincipal を使用してパラメーターを解決するためです。HttpServletRequest#getPrincipal は、リクエストが匿名の場合は null です。

匿名リクエストで Authentication を取得する場合は、代わりに @CurrentSecurityContext を使用してください。

匿名のリクエストには CurrentSecurityContext を使用する
  • Java

  • Kotlin

@GetMapping("/")
public String method(@CurrentSecurityContext SecurityContext context) {
	return context.getAuthentication().getName();
}
@GetMapping("/")
fun method(@CurrentSecurityContext context : SecurityContext) : String =
		context!!.authentication!!.name

1key プロパティの使用は、ここで実際のセキュリティを提供するものと見なされるべきではありません。これは単なる記録管理の練習です。認証クライアントが Authentication オブジェクトを構築することが可能なシナリオ(RMI 呼び出しなど)で AnonymousAuthenticationProvider を含む ProviderManager を共有している場合、悪意のあるクライアントは自身で作成した AnonymousAuthenticationToken を送信できます(選択された状態で)ユーザー名と権限リスト)。key が推測可能である場合、または見つけられる場合、トークンは匿名プロバイダーによって受け入れられます。これは通常の使用では問題ありませんが、RMI を使用している場合は、HTTP 認証メカニズムに使用するプロバイダーを共有するのではなく、匿名プロバイダーを省略するカスタマイズされた ProviderManager を使用するのが最善です。