最新の安定バージョンについては、Spring Security 6.3.1 を使用してください! |
セキュアなオブジェクトの実装
AOP Alliance(MethodInvocation)セキュリティインターセプター
Spring Security 2.0 の前は、MethodInvocation
を固定するには、かなり多くのボイラープレート構成が必要でした。現在、メソッドのセキュリティに推奨されるアプローチは、名前空間の構成を使用することです。このようにして、メソッドセキュリティインフラストラクチャ Bean が自動的に構成されるため、実装クラスについて実際に知る必要はありません。ここでは、関連するクラスの概要を簡単に説明します。
メソッドのセキュリティは、MethodInvocation
を保護する MethodSecurityInterceptor
を使用して実施されます。構成アプローチによっては、インターセプターは単一の Bean に固有であるか、複数の Bean 間で共有される場合があります。インターセプターは、MethodSecurityMetadataSource
インスタンスを使用して、特定のメソッド呼び出しに適用される構成属性を取得します。MapBasedMethodSecurityMetadataSource
は、メソッド名(ワイルドカードを使用可能)をキーとする構成属性を格納するために使用され、<intercept-methods>
または <protect-point>
要素を使用してアプリケーションコンテキストで属性が定義されるときに内部的に使用されます。他の実装を使用して、アノテーションベースの構成を処理します。
明示的な MethodSecurityInterceptor 設定
もちろん、Spring AOP のプロキシメカニズムの 1 つで使用するために、アプリケーションコンテキストで MethodSecurityInterceptor
を直接構成できます。
<bean id="bankManagerSecurity" class=
"org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="accessDecisionManager" ref="accessDecisionManager"/>
<property name="afterInvocationManager" ref="afterInvocationManager"/>
<property name="securityMetadataSource">
<sec:method-security-metadata-source>
<sec:protect method="com.mycompany.BankManager.delete*" access="ROLE_SUPERVISOR"/>
<sec:protect method="com.mycompany.BankManager.getBalance" access="ROLE_TELLER,ROLE_SUPERVISOR"/>
</sec:method-security-metadata-source>
</property>
</bean>
AspectJ(JoinPoint)セキュリティインターセプター
AspectJ セキュリティインターセプターは、前のセクションで説明した AOP Alliance セキュリティインターセプターと非常によく似ています。実際、このセクションの違いについてのみ説明します。
AspectJ インターセプターの名前は AspectJSecurityInterceptor
です。Spring アプリケーションコンテキストに依存してプロキシ経由でセキュリティインターセプターを織り込む AOP Alliance セキュリティインターセプターとは異なり、AspectJSecurityInterceptor
は AspectJ コンパイラー経由で織り込まれています。同じアプリケーションで両方の型のセキュリティインターセプターを使用することは珍しくありません。AspectJSecurityInterceptor
はドメインオブジェクトインスタンスのセキュリティに使用され、AOP Alliance MethodSecurityInterceptor
はサービスレイヤーのセキュリティに使用されます。
まず、AspectJSecurityInterceptor
が Spring アプリケーションコンテキストでどのように構成されているかを考えてみましょう。
<bean id="bankManagerSecurity" class=
"org.springframework.security.access.intercept.aspectj.AspectJMethodSecurityInterceptor">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="accessDecisionManager" ref="accessDecisionManager"/>
<property name="afterInvocationManager" ref="afterInvocationManager"/>
<property name="securityMetadataSource">
<sec:method-security-metadata-source>
<sec:protect method="com.mycompany.BankManager.delete*" access="ROLE_SUPERVISOR"/>
<sec:protect method="com.mycompany.BankManager.getBalance" access="ROLE_TELLER,ROLE_SUPERVISOR"/>
</sec:method-security-metadata-source>
</property>
</bean>
ご覧のとおり、クラス名を除き、AspectJSecurityInterceptor
は AOP Alliance のセキュリティインターセプターとまったく同じです。実際、SecurityMetadataSource
は AOP ライブラリ固有のクラスではなく java.lang.reflect.Method
で動作するため、2 つのインターセプターは同じ securityMetadataSource
を共有できます。もちろん、アクセスの決定は、関連する AOP ライブラリ固有の呼び出し(つまり MethodInvocation
または JoinPoint
)にアクセスできるため、アクセスの決定(メソッドの引数など)を行う際に追加の条件の範囲を考慮することができます。
次に、AspectJ aspect
を定義する必要があります。例:
package org.springframework.security.samples.aspectj;
import org.springframework.security.access.intercept.aspectj.AspectJSecurityInterceptor;
import org.springframework.security.access.intercept.aspectj.AspectJCallback;
import org.springframework.beans.factory.InitializingBean;
public aspect DomainObjectInstanceSecurityAspect implements InitializingBean {
private AspectJSecurityInterceptor securityInterceptor;
pointcut domainObjectInstanceExecution(): target(PersistableEntity)
&& execution(public * *(..)) && !within(DomainObjectInstanceSecurityAspect);
Object around(): domainObjectInstanceExecution() {
if (this.securityInterceptor == null) {
return proceed();
}
AspectJCallback callback = new AspectJCallback() {
public Object proceedWithObject() {
return proceed();
}
};
return this.securityInterceptor.invoke(thisJoinPoint, callback);
}
public AspectJSecurityInterceptor getSecurityInterceptor() {
return securityInterceptor;
}
public void setSecurityInterceptor(AspectJSecurityInterceptor securityInterceptor) {
this.securityInterceptor = securityInterceptor;
}
public void afterPropertiesSet() throws Exception {
if (this.securityInterceptor == null)
throw new IllegalArgumentException("securityInterceptor required");
}
}
}
上記の例では、セキュリティインターセプターは PersistableEntity
のすべてのインスタンスに適用されますが、これは示されていない抽象クラスです(他のクラスまたは pointcut
式を使用できます)。proceed();
ステートメントは around()
本体内でのみ特別な意味を持つため、好奇心の強い人には AspectJCallback
が必要です。AspectJSecurityInterceptor
は、ターゲットオブジェクトを継続させたいときに、この匿名 AspectJCallback
クラスを呼び出します。
アスペクトをロードして AspectJSecurityInterceptor
に接続するように Spring を構成する必要があります。これを実現する Bean 宣言を以下に示します。
<bean id="domainObjectInstanceSecurityAspect"
class="security.samples.aspectj.DomainObjectInstanceSecurityAspect"
factory-method="aspectOf">
<property name="securityInterceptor" ref="bankManagerSecurity"/>
</bean>
以上です! これで、アプリケーション内の任意の場所から Bean を作成できます。new Person();
などの適切な手段を使用すると、セキュリティインターセプターが適用されます。