2013-02-27 5 views
9

アノテーションとスプリングセキュリティを使用して、オープンソースプロジェクトにメソッドレベルのセキュリティを追加しようとしています。私が直面している問題は、特にページングのためのfindAllメソッド(例えば、ページを返す)です。Spring Data JPAとスプリングセキュリティ:データベースレベルのフィルタ(特にページング用)

@PostFilterをListで使用すると(個人的には、データベースではなくアプリケーションでフィルタリングするのは良い考えではありませんが)、ページングクエリでは完全に失敗します。

エンティティにList<Compound>が含まれているため、これは問題があります。化合物のさまざまな実装があり、ユーザーは化合物の1つを読み取る特権しか持たないかもしれません。化合物はTABLE_PER_CLASS継承を使用します。リポジトリにはQueryDslPredicateExecutorが実装されています。

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

+0

質問については、[User Schema](http://static.springsource.org/spring-security/site/docs/3.2.x/reference/springsecurity-single.html#d0e8380)セクションを参照してください。 –

+0

現在のユーザーの役割を考慮してクエリを調整することができます(例:特定のエンティティからロールへの関係とロールからユーザーへの関係が必要です。 –

+0

次に、ACL http://static.springsource.org/spring-security/site/docs/3.2.x/reference/springsecurity-single.html#domain-aclsと適切なDBスキーマhttp:// staticを見てください。 springsource.org/spring-security/site/docs/3.2.x/reference/springsecurity-single.html#dbschema-acl –

答えて

2

当面、以下の解決策が出ました。私のプロジェクトはかなり単純なので、これはもっと複雑なプロジェクトではうまくいかないかもしれません。

  1. ユーザは、すべてのまたは特定のクラスのエンティティしたがって

のいずれも任意のクエリ方法はhasRoleを含む@PreAuthorizeで注釈することができる読み取ることができます。

例外は、私のプロジェクトのContainerエンティティです。 Compoundのサブクラスを含めることができ、ユーザーはそれらのすべてを表示する特権を持たない可能性があります。フィルターにする必要があります。

私はUserRoleエンティティを作成しました。 Compoundは、RoleへのOneToOneの関係を持ち、その役割は、そのCompoundの "read_role"です。 UserRoleにはManyToMany関係があります。

@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からUserにQueryDSLパスを初期化する必要があります。

@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につながることができます。

さらにヒント:

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) 

これは動作します:CompoundServiceは自動的に保存上の役割を設定します。欠点は少し明らかです。同じRoleは、同じCompoundクラス実装のすべての単一インスタンスに関連付けられています。

6

現在、このようなサポートはありませんが、ロードマップ上に掲載しています。一般的な進歩については、DATACMNS-293に従ってください。

関連する問題