1. 概要

この記事では、@PreFilterおよび@PostFilterアノテーションを使用して、Springアプリケーションの操作を保護する方法を学習します。

@PreFilterおよび@PostFilterを認証されたプリンシパル情報と一緒に使用すると、SpringExpressionLanguageを使用してきめ細かいセキュリティルールを定義できます。

2. @PreFilter@PostFilterのご紹介

簡単に言うと、@PreFilterおよび@PostFilterアノテーションは、定義したカスタムセキュリティルールに基づいてオブジェクトのリストをフィルタリングするために使用されます。

@PostFilter は、リスト内のすべての要素にそのルールを適用することにより、メソッドの戻りリストをフィルタリングするためのルールを定義します。 評価された値がtrueの場合、アイテムはリストに保持されます。 それ以外の場合、アイテムは削除されます。

@PreFilter は非常によく似た方法で機能しますが、フィルタリングは、注釈付きメソッドへの入力パラメーターとして渡されるリストに適用されます。

両方のアノテーションは、メソッドまたはタイプ(クラスとインターフェース)で使用できます。 この記事全体を通して、メソッドでのみ使用します。

これらのアノテーションはデフォルトではアクティブではありません。セキュリティ構成で@EnableGlobalMethodSecurityアノテーションとprePostEnabled=trueを使用してアノテーションを有効にする必要があります。

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    // ...
}

3. セキュリティルールの作成

これらの2つの注釈にセキュリティルールを記述するために、Spring-EL式を使用します。 組み込みオブジェクトfilterObjectを使用して、テスト対象の特定のリスト要素への参照を取得することもできます。

Spring Securityは、他の多くの組み込みオブジェクトを提供して、非常に具体的で正確なルールを作成します。

たとえばの場合、 @PreFilter を使用して、Taskオブジェクトのassigneeプロパティがnameと等しいかどうかを確認できます。現在認証されているユーザーの

@PostFilter("filterObject.assignee == authentication.name")
List<Task> findAll() {
    ...
}

ここでは@PostFilterアノテーションを使用しました。これは、メソッドが最初にすべてのタスクを実行して取得し、リストのすべてのタスクをフィルタールールに渡すためです。

したがって、認証されたユーザーが michael の場合、 findAll メソッドによって返されるタスクの最終リストには、michaelに割り当てられているタスクのみが含まれます。データベースには、jimおよびpamに割り当てられたタスクがあります。

それでは、ルールをもう少し面白くしましょう。 ユーザーがマネージャーである場合、誰に割り当てられているかに関係なく、すべてのタスクを表示できると想定します。

@PostFilter("hasRole('MANAGER') or filterObject.assignee == authentication.name")
List<Task> findAll() {
    // ...
}

組み込みのメソッドhasRoleを使用して、認証されたユーザーがMANAGERの役割を持っているかどうかを確認しました。 hasRole がtrueを返す場合、タスクは最終リストに保持されます。 したがって、ユーザーがマネージャーの場合、ルールはリスト内のすべてのアイテムに対してtrueを返します。 したがって、最終的なリストにはすべてのアイテムが含まれます。

次に、 @PreFilter を使用して、saveメソッドにパラメーターとして渡されたリストをフィルター処理しましょう。

@PreFilter("hasRole('MANAGER') or filterObject.assignee == authentication.name")
Iterable<Task> save(Iterable<Task> entities) {
    // ...
}

セキュリティルールは、@PostFilterの例で使用したものと同じです。 ここでの主な違いは、メソッドが実行される前にリストアイテムがフィルタリングされるため、リストから一部のアイテムを削除して、データベースに保存できないようにすることです。

そのため、マネージャーではない jim は、タスクのリストを保存しようとする場合があり、その一部はpamに割り当てられています。 ただし、 jim に割り当てられたタスクのみが含まれ、他のタスクは無視されます。

4. 大規模なリストでのパフォーマンス

@PreFilter は非常にクールで使いやすいですが、フェッチ操作によってすべてのデータが取得され、後でフィルターが適用されるため、非常に大きなリストを処理する場合は非効率になる可能性があります。

たとえば、データベースに数千のタスクがあり、現在pamに割り当てられている5つのタスクを取得するとします。 @PreFilter を使用する場合、データベース操作は最初にすべてのタスクをフェッチし、それらすべてを反復処理して、pamに割り当てられていないタスクを除外します。 ]。

5. 結論

この簡単な記事では、SpringSecurityの@PreFilterおよび@PostFilterアノテーションを使用してシンプルで安全なアプリケーションを作成する方法について説明しました。

このGithubリポジトリの完全なコード例を確認してください。