11

注釈とスプリング セキュリティを使用して、オープン ソース プロジェクトにメソッド レベルのセキュリティを追加しようとしています。私が今直面している問題は、findAll メソッド、特にページング用のものです (例: ページを返す)。

@PostFilter を使用すると、リストで機能します (ただし、データベースではなくアプリケーションでフィルター処理することはお勧めできません) が、ページング クエリでは完全に失敗します。

を含むエンティティがあるため、これは問題ですList<Compound>。コンパウンドにはさまざまな実装があり、ユーザーはコンパウンドの 1 つを読み取る権限しか持たない場合があります。複合はTABLE_PER_CLASS継承を使用します。リポジトリは実装しQueryDslPredicateExecutorます。

私の考えは、現在のユーザーに基づいて返される結果を制限する述語を各クエリに追加することです。ただし、a)ユーザーとロールのデータモデルがどのように見えるか、およびb)述語を作成する方法については、ちょっと迷っています(モデルが定義されれば、これはおそらく簡単です)。または、querydsl は既に型ベースのフィルタリング (クエリ対象のクラスに含まれる要素) を提供していますか?

4

3 に答える 3

7

現在、そのようなサポートはありませんが、ロードマップにはあります。一般的な進捗状況については、 DATACMNS-293をフォローすることをお勧めします。

于 2013-02-28T09:19:16.500 に答える
2

とりあえず以下の解決策を思いつきました。私のプロジェクトはかなり単純なので、これはより複雑なプロジェクトではうまくいかないかもしれません。

  1. ユーザーは、特定のクラスのエンティティをすべて読み取るか、まったく読み取ることができません。

したがって、任意のクエリ メソッドに を@PreAuthorize含むアノテーションを付けることができますhasRole

これに対する例外は、Container私のプロジェクトのエンティティです。のサブクラスを含めることができCompound、ユーザーはそれらすべてを表示する権限を持っていない場合があります。それらはフィルターでなければなりません。

そのために、UserandRoleエンティティを作成しました。Compoundと OneToOne の関係がRoleあり、そのロールはその の「read_role」ですCompound。多対多の関係がありますUserRole

@Entity
public abstract class Compound {    
    //...
    @OneToOne    
    private Role readRole;
    //...   
}

私のリポジトリはすべて実装されQueryDSLPredicateExecutorており、ここでは非常に便利です。リポジトリでカスタムの findBy メソッドを作成する代わりに、サービス レイヤーでのみ作成し、 と を使用repositry.findAll(predicate)repository.findOne(predicate)ます。述語は、実際のユーザー入力と「セキュリティ フィルター」を保持します。

@PreAuthorize("hasRole('read_Container'")
public T getById(Long id) {        
    Predicate predicate = QCompoundContainer.compoundContainer.id.eq(id);
    predicate = addSecurityFilter(predicate);
    T container = getRepository().findOne(predicate);        
    return container;
}

private Predicate addSecurityFilter(Predicate predicate){        
    String userName = SecurityContextHolder.getContext().getAuthentication().getName();            
    predicate = QCompoundContainer.compoundContainer.compound.readRole
        .users.any().username.eq(userName).and(predicate);        
    return predicate;
}

注:QCompoundContainerは、QueryDSL によって生成される「メタモデル」クラスです。

最後に、おそらく からContainerへの QueryDSL パスを初期化する必要がありUserます。

@Entity
public abstract class CompoundContainer<T extends Compound> 
    //...
    @QueryInit("readRole.users") // INITIALIZE QUERY PATH
    @ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL,
            targetEntity=Compound.class)
    private T compound;
    //...
}

この最後の手順を省略すると、NullPointerException.

さらなるヒント:CompoundService保存時にロールを自動的に設定します:

if (compound.getReadRole() == null) {
    Role role = roleRepository.findByRoleName("read_" + getCompoundClassSimpleName());
    if (role == null) {
        role = new Role("read_" + getCompoundClassSimpleName());
        role = roleRepository.save(role);
    }
    compound.setReadRole(role);
}
compound = getRepository().save(compound)

これは機能します。欠点は少し明白です。同じことが、同じクラス実装Roleのすべてのインスタンスに関連付けられています。Compound

于 2013-02-28T13:36:15.787 に答える