6

TL; DR:我如何在Spring-Data-Rest提供的扁平化REST API方法中實現細粒度的訪問控制?如何在Spring-Data-Rest中實現細粒度的訪問控制?

所以 - 我正在使用Spring的數據休息,其中有三個主要的訪問級別的API:

1)管理 - 可以看到/更新所有組

2)的所有者組 - 可以看到/更新組,一切都在它之下

3)子組的所有者 - 可以看到/只更新他的小組。沒有遞歸嵌套,只允許一個子級別。

和「基團」被暴露作爲資源(具有污物儲存庫)。

到目前爲止好 - 我已經實現了使用信息庫事件處理程序修改了一些訪問控制 - 因此在創建/寫入/刪除身邊,我覺得我很好。

現在我需要去限制某些項目的可見性的點。由於我可以使用Pre/Post Authorize註釋並引用委託人,因此獲取單個項目是可以的。

的問題就出在的findAll()方法 - 我沒有一個簡單的鉤來過濾掉特定的情況下,我不希望根據當前的主要暴露出來。例如 - 小組所有者可以通過執行GET /組來查看所有組。理想情況下,他們應該擁有他們無法訪問的項目,甚至根本不可見。

對我來說,這聽起來像在庫接口編寫自定義@Query()註解,但似乎可行不會因爲:

  • 我需要引用主查詢。 SPeL應該被支持,但似乎完全不能用##表達式(儘管這篇博客文章提出了另外的建議:https://spring.io/blog/2014/07/15/spel-support-in-spring-data-jpa-query-definitions)。我一般使用1.1.8.RELEASE和Evans-RELEASE訓練彈簧數據。

  • 根據訪問級別的不同,我需要編寫的查詢將會有所不同,但不能實際包含在單個JPQL語句中(如果管理員選擇所有組,則會獲取所有(子)組與委託人的用戶相關聯)。

因此,它聽起來像我需要編寫一些自定義存儲庫實現,只是參考代碼中的委託人。沒關係 - 但是對於每個需要控制訪問權限的存儲庫來說,這看起來像是很多工作(我認爲這幾乎全部都是這些)。這適用於findAll和各種自定義搜索方法。

我接近這個錯誤嗎?是否有另一種方法來基於當前登錄的用戶動態限制項目可見性,這會更好地工作?在像spring-data-rest這樣的平面命名空間中,我會想象這是一個常見問題。

在之前的設計中,我剛剛通過暴露/ api/groups/{groupId}/...下的所有內容來解決它,並將子資源定位器用作控制對其下任何內容的訪問的單個夾點。在spring-data-rest中沒有這樣的運氣。

更新:現在有一個自定義的方法覆蓋的findAll()絆(這種方式更適合我的自定義接口上定義的其他方法)。雖然這可能是一個單獨的問題 - 我現在被阻止。當我做一個GET /組時,Spring-data並沒有調用它,而是調用原始的。奇怪的是,它使用我的查詢,如果我在界面上定義一個,並用@Query標記它(也許自定義覆蓋的內置方法不再受支持?)。

public interface GroupRepository extends JpaRepository<Group, Long>, GroupCustomRepository {} 


public interface GroupCustomRepository { 

    Page<Group> findAll(Pageable pageable); 

} 

public class GroupCustomRepositoryImpl extends SimpleJpaRepository<Group, Long> implements GroupCustomRepository { 

    @Inject 
    public GroupCustomRepositoryImpl(EntityManager em) { 
     super(Group.class, em); 
    } 

    @Override 
    public Page<Group> findAll(Pageable pageable) { 

     MyPrincipal principal = (MyPrincipal) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); 

     Page<Group> result; 
     if (principal.isAdmin()) { 
      result = findAll(pageable); 
     } else { 

      Specification<Group> spec = (root, query, cb) -> cb.or(
       cb.equal(root, principal.getGroup()), 
       cb.and(cb.isNotNull(root.get(Group_.parentGroup)), cb.equal(root.get(Group_.parentGroup), principal.getGroup())) 
      ); 

      result = findAll(spec, pageable); 
     } 

     return result; 
    } 
} 

更新2:既然不能訪問主要在@Query,我不能與一個自定義的方法來覆蓋它,我在磚牆。 @PostFilter不起作用,因爲返回對象是一個頁面而不是一個集合。

我決定只將/組隔離到管理員,並讓其他人使用@ PostFilters/@ PostAuthorizations使用不同的方法(/ groups/search/somethingSpecific)。

雖然這看起來並不像它與HAL方法非常吻合。對其他人如何用Spring-data-rest解決這些問題感興趣。

+0

你不能使用'@ PostFilter'嗎? BTW有多個'findAll'方法。壓倒一個可能還不夠。 – zeroflagL 2014-10-30 08:33:17

+0

試過:) @PostFilter不能和頁面一起工作 - 並且無論如何都會拋出頁面邏輯(並且可能性能很差)。看起來你只應該重寫findAll()的一個 - 否則它會將它們視爲模糊的路徑。我不知道我甚至可以支持排序和分頁,如果我只是重寫其中一種方法。 – 2014-10-30 16:46:12

+0

你們每個人都找到了這個@DaveLeBlanc的解決方案嗎? – 2015-06-11 21:32:27

回答

3

我們結束了接近這一如下:

  • 我們創建了坐落在中上的存儲庫的CRUD方法前的自定義方面。然後它查找並調用相關的「授權處理程序」,該程序在存儲庫上進行註釋,以動態管理授權詳細信息。我們不得不在一個findAll()查詢中限制結果(例如:看着/用戶) - 在本質上,只有管理員可以列出所有敏感的東西,所以我們不得不相當強硬。否則,有限的用戶不得不針對特定項目使用查詢方法。

  • 我們創造了一些可重複使用的授權相關的類,並使用這些在某些情況下 - 特別是自定義查詢,例如:

    @PreAuthorize( 「@ authorizations.systemAdminRead()」) @Query(「選擇[u] FROM User r where ...「) List findAll();

    @PostAuthorize(「@ otherAuthorizationHandler.readAllowed(returnObject)」)ResponseObject someQuery();

總而言之,它的工作原理 - 但它感覺非常笨重,而且很容易錯過。我希望這可以更多地融入到框架中,即使能夠動態調整默認查詢也是有用的(當我嘗試這樣做時,我無法使用@Query更新相應的查詢)。

我們恰好​​在使用PostgreSQL,所以即將推出的行級安全性(http://michael.otacoo.com/postgresql-2/postgres-9-5-feature-highlight-row-level-security/)可以很好地適應賬單,假設我們可以通過數據庫連接向它提供適當的授權細節。

相關問題