最新の安定バージョンについては、Spring Security 6.4.4 を使用してください! |
メソッドのセキュリティ
バージョン 2.0 以降、Spring Security は、サービスレイヤーメソッドにセキュリティを追加するためのサポートを大幅に改善しました。JSR-250 アノテーションセキュリティとフレームワークの元の @Secured
アノテーションのサポートを提供します。3.0 から、新しい式ベースのアノテーションを利用することもできます。intercept-methods
要素を使用して Bean 宣言を装飾することにより、単一の Bean にセキュリティを適用するか、AspectJ スタイルのポイントカットを使用してサービス層全体にわたって複数の Bean を保護することができます。
EnableMethodSecurity
Spring Security 5.6 では、任意の @Configuration
インスタンスで @EnableMethodSecurity
アノテーションを使用して、アノテーションベースのセキュリティを有効にできます。
これは、いくつかの点で @EnableGlobalMethodSecurity
を改善します。@EnableMethodSecurity
:
メタデータソース、構成属性、意思決定マネージャー、投票者の代わりに、簡略化された
AuthorizationManager
API を使用します。これにより、再利用とカスタマイズが簡単になります。Bean をカスタマイズするために
GlobalMethodSecurityConfiguration
を継承する必要はなく、直接 Bean ベースの構成を優先しますネイティブ Spring AOP を使用して構築され、抽象化を削除し、Spring AOP ビルドブロックを使用してカスタマイズできるようにします
競合するアノテーションをチェックして、明確なセキュリティ構成を確保します
JSR-250 に準拠
デフォルトで
@PreAuthorize
、@PostAuthorize
、@PreFilter
、@PostFilter
を有効にします
以前のバージョンについては、@EnableGlobalMethodSecurity での同様のサポートについて参照してください。 |
例: 次の場合、Spring Security の @PreAuthorize
アノテーションが有効になります。
Java
Kotlin
XML
@EnableMethodSecurity
public class MethodSecurityConfig {
// ...
}
@EnableMethodSecurity
class MethodSecurityConfig {
// ...
}
<sec:method-security/>
(クラスまたはインターフェース上の)メソッドにアノテーションを追加すると、それに応じてそのメソッドへのアクセスが制限されます。Spring Security のネイティブアノテーションサポートは、メソッドの一連の属性を定義します。これらは、実際の決定を行うために DefaultAuthorizationMethodInterceptorChain
に渡されます。
Java
Kotlin
public interface BankService {
@PreAuthorize("hasRole('USER')")
Account readAccount(Long id);
@PreAuthorize("hasRole('USER')")
List<Account> findAccounts();
@PreAuthorize("hasRole('TELLER')")
Account post(Account account, Double amount);
}
interface BankService {
@PreAuthorize("hasRole('USER')")
fun readAccount(id : Long) : Account
@PreAuthorize("hasRole('USER')")
fun findAccounts() : List<Account>
@PreAuthorize("hasRole('TELLER')")
fun post(account : Account, amount : Double) : Account
}
以下を使用して、Spring Security の @Secured
アノテーションのサポートを有効にできます。
Java
Kotlin
XML
@EnableMethodSecurity(securedEnabled = true)
public class MethodSecurityConfig {
// ...
}
@EnableMethodSecurity(securedEnabled = true)
class MethodSecurityConfig {
// ...
}
<sec:method-security secured-enabled="true"/>
または JSR-250 を使用:
Java
Kotlin
XML
@EnableMethodSecurity(jsr250Enabled = true)
public class MethodSecurityConfig {
// ...
}
@EnableMethodSecurity(jsr250Enabled = true)
class MethodSecurityConfig {
// ...
}
<sec:method-security jsr250-enabled="true"/>
認可のカスタマイズ
Spring Security の @PreAuthorize
、@PostAuthorize
、@PreFilter
、@PostFilter
には、表現ベースの豊富なサポートが付属しています。
式の処理方法をカスタマイズする必要がある場合は、次のようにカスタム MethodSecurityExpressionHandler
を公開できます。
Java
Kotlin
XML
@Bean
static MethodSecurityExpressionHandler methodSecurityExpressionHandler() {
DefaultMethodSecurityExpressionHandler handler = new DefaultMethodSecurityExpressionHandler();
handler.setTrustResolver(myCustomTrustResolver);
return handler;
}
companion object {
@Bean
fun methodSecurityExpressionHandler() : MethodSecurityExpressionHandler {
val handler = DefaultMethodSecurityExpressionHandler();
handler.setTrustResolver(myCustomTrustResolver);
return handler;
}
}
<sec:method-security>
<sec:expression-handler ref="myExpressionHandler"/>
</sec:method-security>
<bean id="myExpressionHandler"
class="org.springframework.security.messaging.access.expression.DefaultMessageSecurityExpressionHandler">
<property name="trustResolver" ref="myCustomTrustResolver"/>
</bean>
|
また、ロールベースの認可の場合、Spring Security はデフォルトの ROLE_
プレフィックスを追加します。これは、hasRole
などの式を評価するときに使用されます。
Java
Kotlin
XML
@Bean
static GrantedAuthorityDefaults grantedAuthorityDefaults() {
return new GrantedAuthorityDefaults("MYPREFIX_");
}
companion object {
@Bean
fun grantedAuthorityDefaults() : GrantedAuthorityDefaults {
return GrantedAuthorityDefaults("MYPREFIX_");
}
}
<sec:method-security/>
<bean id="grantedAuthorityDefaults" class="org.springframework.security.config.core.GrantedAuthorityDefaults">
<constructor-arg value="MYPREFIX_"/>
</bean>
|
カスタム認可マネージャー
メソッド認証は、メソッド前とメソッド後の認証を組み合わせたものです。
メソッド前の認可は、メソッドが呼び出される前に実行されます。その認可がアクセスを拒否した場合、メソッドは呼び出されず、 |
@EnableMethodSecurity
の追加がデフォルトで行うことを再現するには、次の構成を公開します。
Java
Kotlin
XML
@EnableMethodSecurity(prePostEnabled = false)
class MethodSecurityConfig {
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
Advisor preFilterAuthorizationMethodInterceptor() {
return new PreFilterAuthorizationMethodInterceptor();
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
Advisor preAuthorizeAuthorizationMethodInterceptor() {
return AuthorizationManagerBeforeMethodInterceptor.preAuthorize();
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
Advisor postAuthorizeAuthorizationMethodInterceptor() {
return AuthorizationManagerAfterMethodInterceptor.postAuthorize();
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
Advisor postFilterAuthorizationMethodInterceptor() {
return new PostFilterAuthorizationMethodInterceptor();
}
}
@EnableMethodSecurity(prePostEnabled = false)
class MethodSecurityConfig {
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
fun preFilterAuthorizationMethodInterceptor() : Advisor {
return PreFilterAuthorizationMethodInterceptor();
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
fun preAuthorizeAuthorizationMethodInterceptor() : Advisor {
return AuthorizationManagerBeforeMethodInterceptor.preAuthorize();
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
fun postAuthorizeAuthorizationMethodInterceptor() : Advisor {
return AuthorizationManagerAfterMethodInterceptor.postAuthorize();
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
fun postFilterAuthorizationMethodInterceptor() : Advisor {
return PostFilterAuthorizationMethodInterceptor();
}
}
<sec:method-security pre-post-enabled="false"/>
<aop:config/>
<bean id="preFilterAuthorizationMethodInterceptor"
class="org.springframework.security.authorization.method.PreFilterAuthorizationMethodInterceptor"/>
<bean id="preAuthorizeAuthorizationMethodInterceptor"
class="org.springframework.security.authorization.method.AuthorizationManagerBeforeMethodInterceptor"
factory-method="preAuthorize"/>
<bean id="postAuthorizeAuthorizationMethodInterceptor"
class="org.springframework.security.authorization.method.AuthorizationManagerAfterMethodInterceptor"
factory-method="postAuthorize"/>
<bean id="postFilterAuthorizationMethodInterceptor"
class="org.springframework.security.authorization.method.PostFilterAuthorizationMethodInterceptor"/>
Spring Security のメソッドセキュリティは Spring AOP を使用して構築されていることに注意してください。インターセプターは指定された順序に基づいて呼び出されます。これは、次のようにインターセプターインスタンスで setOrder
を呼び出すことによってカスタマイズできます。
Java
Kotlin
XML
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
Advisor postFilterAuthorizationMethodInterceptor() {
PostFilterAuthorizationMethodInterceptor interceptor = new PostFilterAuthorizationMethodInterceptor();
interceptor.setOrder(AuthorizationInterceptorOrders.POST_AUTHORIZE.getOrder() - 1);
return interceptor;
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
fun postFilterAuthorizationMethodInterceptor() : Advisor {
val interceptor = PostFilterAuthorizationMethodInterceptor();
interceptor.setOrder(AuthorizationInterceptorOrders.POST_AUTHORIZE.getOrder() - 1);
return interceptor;
}
<bean id="postFilterAuthorizationMethodInterceptor"
class="org.springframework.security.authorization.method.PostFilterAuthorizationMethodInterceptor">
<property name="order"
value="#{T(org.springframework.security.authorization.method.AuthorizationInterceptorsOrder).POST_AUTHORIZE.getOrder() -1}"/>
</bean>
アプリケーションで @PreAuthorize
のみをサポートしたい場合は、次のようにすることができます。
Java
Kotlin
XML
@EnableMethodSecurity(prePostEnabled = false)
class MethodSecurityConfig {
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
Advisor preAuthorize() {
return AuthorizationManagerBeforeMethodInterceptor.preAuthorize();
}
}
@EnableMethodSecurity(prePostEnabled = false)
class MethodSecurityConfig {
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
fun preAuthorize() : Advisor {
return AuthorizationManagerBeforeMethodInterceptor.preAuthorize()
}
}
<sec:method-security pre-post-enabled="false"/>
<aop:config/>
<bean id="preAuthorizeAuthorizationMethodInterceptor"
class="org.springframework.security.authorization.method.AuthorizationManagerBeforeMethodInterceptor"
factory-method="preAuthorize"/>
または、リストに追加するカスタムの before-method AuthorizationManager
がある場合があります。
この場合、AuthorizationManager
と、認可マネージャーが適用するメソッドとクラスの両方を Spring Security に通知する必要があります。
次のように、@PreAuthorize
と @PostAuthorize
の間で AuthorizationManager
を呼び出すように Spring Security を構成できます。
Java
Kotlin
XML
@EnableMethodSecurity
class MethodSecurityConfig {
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public Advisor customAuthorize() {
JdkRegexpMethodPointcut pattern = new JdkRegexpMethodPointcut();
pattern.setPattern("org.mycompany.myapp.service.*");
AuthorizationManager<MethodInvocation> rule = AuthorityAuthorizationManager.isAuthenticated();
AuthorizationManagerBeforeMethodInterceptor interceptor = new AuthorizationManagerBeforeMethodInterceptor(pattern, rule);
interceptor.setOrder(AuthorizationInterceptorsOrder.PRE_AUTHORIZE_ADVISOR_ORDER.getOrder() + 1);
return interceptor;
}
}
@EnableMethodSecurity
class MethodSecurityConfig {
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
fun customAuthorize() : Advisor {
val pattern = JdkRegexpMethodPointcut();
pattern.setPattern("org.mycompany.myapp.service.*");
val rule = AuthorityAuthorizationManager.isAuthenticated();
val interceptor = AuthorizationManagerBeforeMethodInterceptor(pattern, rule);
interceptor.setOrder(AuthorizationInterceptorsOrder.PRE_AUTHORIZE_ADVISOR_ORDER.getOrder() + 1);
return interceptor;
}
}
<sec:method-security/>
<aop:config/>
<bean id="customAuthorize"
class="org.springframework.security.authorization.method.AuthorizationManagerBeforeMethodInterceptor">
<constructor-arg>
<bean class="org.springframework.aop.support.JdkRegexpMethodPointcut">
<property name="pattern" value="org.mycompany.myapp.service.*"/>
</bean>
</constructor-arg>
<constructor-arg>
<bean class="org.springframework.security.authorization.AuthorityAuthorizationManager"
factory-method="isAuthenticated"/>
</constructor-arg>
<property name="order"
value="#{T(org.springframework.security.authorization.method.AuthorizationInterceptorsOrder).PRE_AUTHORIZE_ADVISOR_ORDER.getOrder() + 1}"/>
</bean>
|
メソッド後の認可についても同じことができます。メソッド後の認可は、通常、戻り値を分析してアクセスを検証することに関係しています。
例: 次のように、リクエストされたアカウントが実際にログインしたユーザーに属していることを確認するメソッドがある場合があります。
Java
Kotlin
public interface BankService {
@PreAuthorize("hasRole('USER')")
@PostAuthorize("returnObject.owner == authentication.name")
Account readAccount(Long id);
}
interface BankService {
@PreAuthorize("hasRole('USER')")
@PostAuthorize("returnObject.owner == authentication.name")
fun readAccount(id : Long) : Account
}
独自の AuthorizationMethodInterceptor
を指定して、戻り値へのアクセスの評価方法をカスタマイズできます。
例: 独自のカスタムアノテーションがある場合は、次のように構成できます。
Java
Kotlin
XML
@EnableMethodSecurity
class MethodSecurityConfig {
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public Advisor customAuthorize(AuthorizationManager<MethodInvocationResult> rules) {
AnnotationMatchingPointcut pattern = new AnnotationMatchingPointcut(MySecurityAnnotation.class);
AuthorizationManagerAfterMethodInterceptor interceptor = new AuthorizationManagerAfterMethodInterceptor(pattern, rules);
interceptor.setOrder(AuthorizationInterceptorsOrder.POST_AUTHORIZE_ADVISOR_ORDER.getOrder() + 1);
return interceptor;
}
}
@EnableMethodSecurity
class MethodSecurityConfig {
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
fun customAuthorize(rules : AuthorizationManager<MethodInvocationResult>) : Advisor {
val pattern = AnnotationMatchingPointcut(MySecurityAnnotation::class.java);
val interceptor = AuthorizationManagerAfterMethodInterceptor(pattern, rules);
interceptor.setOrder(AuthorizationInterceptorsOrder.POST_AUTHORIZE_ADVISOR_ORDER.getOrder() + 1);
return interceptor;
}
}
<sec:method-security/>
<aop:config/>
<bean id="customAuthorize"
class="org.springframework.security.authorization.method.AuthorizationManagerAfterMethodInterceptor">
<constructor-arg>
<bean class="org.springframework.aop.support.annotation.AnnotationMethodMatcher">
<constructor-arg value="#{T(org.mycompany.MySecurityAnnotation)}"/>
</bean>
</constructor-arg>
<constructor-arg>
<bean class="org.springframework.security.authorization.AuthorityAuthorizationManager"
factory-method="isAuthenticated"/>
</constructor-arg>
<property name="order"
value="#{T(org.springframework.security.authorization.method.AuthorizationInterceptorsOrder).PRE_AUTHORIZE_ADVISOR_ORDER.getOrder() + 1}"/>
</bean>
@PostAuthorize
インターセプターの後に呼び出されます。
EnableGlobalMethodSecurity
@Configuration
インスタンスで @EnableGlobalMethodSecurity
アノテーションを使用して、アノテーションベースのセキュリティを有効にできます。例: 以下は、Spring Security の @Secured
アノテーションを有効にします。
Java
Kotlin
@EnableGlobalMethodSecurity(securedEnabled = true)
public class MethodSecurityConfig {
// ...
}
@EnableGlobalMethodSecurity(securedEnabled = true)
open class MethodSecurityConfig {
// ...
}
(クラスまたはインターフェース上の)メソッドにアノテーションを追加すると、それに応じてそのメソッドへのアクセスが制限されます。Spring Security のネイティブアノテーションサポートは、メソッドの属性セットを定義します。これらは、AccessDecisionManager に渡され、実際の決定が行われます。
Java
Kotlin
public interface BankService {
@Secured("IS_AUTHENTICATED_ANONYMOUSLY")
public Account readAccount(Long id);
@Secured("IS_AUTHENTICATED_ANONYMOUSLY")
public Account[] findAccounts();
@Secured("ROLE_TELLER")
public Account post(Account account, double amount);
}
interface BankService {
@Secured("IS_AUTHENTICATED_ANONYMOUSLY")
fun readAccount(id: Long): Account
@Secured("IS_AUTHENTICATED_ANONYMOUSLY")
fun findAccounts(): Array<Account>
@Secured("ROLE_TELLER")
fun post(account: Account, amount: Double): Account
}
JSR-250 アノテーションのサポートは、次を使用して有効にできます。
Java
Kotlin
@EnableGlobalMethodSecurity(jsr250Enabled = true)
public class MethodSecurityConfig {
// ...
}
@EnableGlobalMethodSecurity(jsr250Enabled = true)
open class MethodSecurityConfig {
// ...
}
これらは標準ベースであり、単純なロールベースの制約を適用できますが、Spring Security のネイティブアノテーションはありません。新しい式ベースの構文を使用するには、次を使用します
Java
Kotlin
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfig {
// ...
}
@EnableGlobalMethodSecurity(prePostEnabled = true)
open class MethodSecurityConfig {
// ...
}
同等の Java コードは
Java
Kotlin
public interface BankService {
@PreAuthorize("isAnonymous()")
public Account readAccount(Long id);
@PreAuthorize("isAnonymous()")
public Account[] findAccounts();
@PreAuthorize("hasAuthority('ROLE_TELLER')")
public Account post(Account account, double amount);
}
interface BankService {
@PreAuthorize("isAnonymous()")
fun readAccount(id: Long): Account
@PreAuthorize("isAnonymous()")
fun findAccounts(): Array<Account>
@PreAuthorize("hasAuthority('ROLE_TELLER')")
fun post(account: Account, amount: Double): Account
}
GlobalMethodSecurityConfiguration
@EnableGlobalMethodSecurity
アノテーションで許可されるよりも複雑な操作を実行する必要がある場合があります。これらのインスタンスでは、GlobalMethodSecurityConfiguration
を継承して、@EnableGlobalMethodSecurity
アノテーションがサブクラスに存在することを確認できます。例: カスタム MethodSecurityExpressionHandler
を提供する場合、次の構成を使用できます。
Java
Kotlin
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
@Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
// ... create and return custom MethodSecurityExpressionHandler ...
return expressionHandler;
}
}
@EnableGlobalMethodSecurity(prePostEnabled = true)
open class MethodSecurityConfig : GlobalMethodSecurityConfiguration() {
override fun createExpressionHandler(): MethodSecurityExpressionHandler {
// ... create and return custom MethodSecurityExpressionHandler ...
return expressionHandler
}
}
オーバーライドできるメソッドの詳細については、GlobalMethodSecurityConfiguration
Javadoc を参照してください。
<global-method-security> 要素
この要素は、(要素に適切な属性を設定することにより)アプリケーションでアノテーションベースのセキュリティを有効にし、アプリケーションコンテキスト全体に適用されるセキュリティポイントカット宣言をグループ化するために使用されます。<global-method-security>
要素を 1 つだけ宣言する必要があります。次の宣言により、Spring Security の @Secured
のサポートが有効になります。
<global-method-security secured-annotations="enabled" />
(クラスまたはインターフェース上の)メソッドにアノテーションを追加すると、それに応じてそのメソッドへのアクセスが制限されます。Spring Security のネイティブアノテーションサポートは、メソッドの属性セットを定義します。これらは、実際の決定を行うために AccessDecisionManager
に渡されます。
Java
Kotlin
public interface BankService {
@Secured("IS_AUTHENTICATED_ANONYMOUSLY")
public Account readAccount(Long id);
@Secured("IS_AUTHENTICATED_ANONYMOUSLY")
public Account[] findAccounts();
@Secured("ROLE_TELLER")
public Account post(Account account, double amount);
}
interface BankService {
@Secured("IS_AUTHENTICATED_ANONYMOUSLY")
fun readAccount(id: Long): Account
@Secured("IS_AUTHENTICATED_ANONYMOUSLY")
fun findAccounts(): Array<Account>
@Secured("ROLE_TELLER")
fun post(account: Account, amount: Double): Account
}
JSR-250 アノテーションのサポートは、次を使用して有効にできます。
<global-method-security jsr250-annotations="enabled" />
これらは標準ベースであり、単純なロールベースの制約を適用できますが、Spring Security のネイティブアノテーションはありません。新しい式ベースの構文を使用するには、次を使用します
<global-method-security pre-post-annotations="enabled" />
同等の Java コードは
Java
Kotlin
public interface BankService {
@PreAuthorize("isAnonymous()")
public Account readAccount(Long id);
@PreAuthorize("isAnonymous()")
public Account[] findAccounts();
@PreAuthorize("hasAuthority('ROLE_TELLER')")
public Account post(Account account, double amount);
}
interface BankService {
@PreAuthorize("isAnonymous()")
fun readAccount(id: Long): Account
@PreAuthorize("isAnonymous()")
fun findAccounts(): Array<Account>
@PreAuthorize("hasAuthority('ROLE_TELLER')")
fun post(account: Account, amount: Double): Account
}
式ベースのアノテーションは、ユーザーの権限リストに対するロール名のチェックにとどまらない単純なルールを定義する必要がある場合に適しています。
アノテーション付きメソッドは、Spring Bean として定義されているインスタンスに対してのみ保護されます(メソッドセキュリティが有効になっている同じアプリケーションコンテキスト内)。Spring によって作成されていないインスタンスを保護する場合(たとえば、 |
同じアプリケーションで複数の型のアノテーションを有効にできますが、他の方法では動作が適切に定義されないため、インターフェースまたはクラスには 1 つの型のみを使用する必要があります。特定のメソッドに適用される 2 つのアノテーションが見つかった場合、そのうちの 1 つだけが適用されます。 |
protect-pointcut を使用したセキュリティポイントカットの追加
protect-pointcut
の使用は、単純な宣言のみで多くの Bean にセキュリティを適用できるため、特に強力です。次の例を考えてみましょう。
<global-method-security>
<protect-pointcut expression="execution(* com.mycompany.*Service.*(..))"
access="ROLE_USER"/>
</global-method-security>
これにより、クラスが com.mycompany
パッケージにあり、クラス名が "Service" で終わるアプリケーションコンテキストで宣言された Bean のすべてのメソッドが保護されます。ROLE_USER
ロールを持つユーザーのみがこれらのメソッドを呼び出すことができます。URL マッチングと同様に、最初のマッチング表現が使用されるため、ポイントカットのリストで最も具体的な一致が最初に来る必要があります。セキュリティアノテーションはポイントカットよりも優先されます。