2013-02-27 31 views
9

Tôi đang cố gắng thêm bảo mật mức phương thức vào dự án nguồn mở của tôi bằng cách sử dụng chú thích và bảo mật mùa xuân. Vấn đề tôi đang phải đối mặt là findAll phương pháp đặc biệt là những người cho Paging (ví dụ như trả lại một trang).Dữ liệu mùa xuân JPA và bảo mật mùa xuân: lọc theo cấp cơ sở dữ liệu (đặc biệt là để phân trang)

Sử dụng @PostFilter hoạt động trên Danh sách (nhưng cá nhân tôi tin rằng không nên lọc trong ứng dụng chứ không phải cơ sở dữ liệu) nhưng hoàn toàn thất bại khi truy vấn phân trang.

Đây là vấn đề vì tôi có Pháp nhân chứa List<Compound>. Có các triển khai khác nhau của hợp chất và người dùng chỉ có thể có đặc quyền để đọc một trong các Hợp chất. Hợp chất sử dụng TABLE_PER_CLASS kế thừa. Các kho lưu trữ thực hiện QueryDslPredicateExecutor.

Suy nghĩ của tôi là thêm biến vị ngữ vào mỗi truy vấn giới hạn kết quả trả về dựa trên người dùng hiện tại. Tuy nhiên tôi là loại mất trên a) làm thế nào mô hình dữ liệu cho người dùng và vai trò nên xem xét và b) làm thế nào để sau đó tạo ra các vị ngữ (điều này có lẽ dễ dàng khi mô hình được xác định). Hoặc querydsl đã cung cấp lọc dựa trên loại (trên các phần tử chứa trong lớp được truy vấn)?

+0

Đối với câu hỏi A see [User Schema] (http://static.springsource.org/spring-security/site/docs/3.2.x/reference/springsecurity-single.html#d0e8380]) phần –

+0

Ý tôi là tôi có thể điều chỉnh các truy vấn để xem xét vai trò của người dùng hiện tại, ví dụ: phải có mối quan hệ từ một thực thể nhất định với vai trò và từ vai trò đến người dùng. –

+0

Sau đó, hãy xem ACL http://static.springsource.org/spring-security/site/docs/3.2.x/reference/springsecurity-single.html#domain-acls và lược đồ DB thích hợp http: // tĩnh. springsource.org/spring-security/site/docs/3.2.x/reference/springsecurity-single.html#dbschema-acl –

Trả lời

2

Hiện tại đã có giải pháp sau. Vì dự án của tôi khá đơn giản nên điều này có thể không hoạt động cho một dự án phức tạp hơn.

  1. người dùng có thể hoặc là đọc tất cả hoặc không ai trong số các đối tượng của một lớp nào đó

do đó bất kỳ phương pháp truy vấn có thể được chú thích với @PreAuthorize chứa hasRole.

Trường hợp ngoại lệ là thực thể Container trong dự án của tôi. Nó có thể chứa bất kỳ lớp con nào của Compound và người dùng có thể không có đặc quyền để xem tất cả chúng. Chúng phải là bộ lọc.

Vì điều đó tôi đã tạo một thực thể UserRole. Compound có mối quan hệ OneToOne với Role và vai trò đó là "read_role" cho số Compound đó. UserRole có mối quan hệ ManyToMany.

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

Tất cả kho lưu trữ của tôi thực hiện QueryDSLPredicateExecutor và rất dễ dàng ở đây. Thay vì tạo các phương thức findBy tùy chỉnh trong kho lưu trữ, chúng tôi chỉ tạo chúng trong lớp dịch vụ và sử dụng repositry.findAll(predicate)repository.findOne(predicate). Vị từ giữ đầu vào người dùng thực tế + "bộ lọc bảo mật".

@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; 
} 

Lưu ý: QCompoundContainer là lớp "meta-mô hình" được tạo ra bởi QueryDSL.

Cuối cùng bạn có thể cần phải khởi tạo con đường QueryDSL từ Container để 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; 
    //... 
} 

Bỏ bước cuối cùng này có thể dẫn đến một NullPointerException.

Tiếp tục gợi ý: CompoundService tự động thiết lập vai trò trên tiết kiệm:

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) 

này hoạt động. Nhược điểm là một chút rõ ràng. Cùng một Role được liên kết với mọi trường hợp duy nhất của cùng một thực hiện lớp Compound.

6

Hiện tại, không có hỗ trợ như vậy nhưng chúng tôi có nó trên lộ trình. Bạn có thể muốn theo dõi DATACMNS-293 để có tiến bộ chung.