簡體   English   中英

授權數據庫級別的數據訪問

[英]Authorize data access at database level

從問題標題中,您可能會猜到這是什么意思。 我將嘗試描述當前擁有的內容以及要存檔的內容。

假設一個應用程序處理四個實體: UserTeamRepositoryDocument 這些實體之間的關系是:

  • 每個用戶屬於零個或多個團隊
  • 每個文檔都屬於一個存儲庫
  • 用戶可能擁有零個或多個存儲庫
  • 每個存儲庫都可以創建為公共私有
  • 與存儲庫所有者共享團隊的所有用戶都可以看到公共存儲庫的內容。
  • 私有存儲庫僅對其所有者可見。

訪問用戶的文檔不是問題,這些都是存儲在他擁有的存儲庫中的所有文檔。 但是事情變得復雜了,因為我真正需要的是用戶可見的所有文檔,這就是所有文檔以及其他人公開並與他共享團隊的文檔。

目前,我正在數據訪問層中強制執行此授權機制。 這意味着要獲取所有文檔並按照上述規則進行一些過濾。 我知道此實現無法擴展,並且我想知道是否可以通過將授權邏輯移至數據庫來改善數據庫模型。 這樣,過濾將由數據庫引擎完成,並且只有請求的實體將返回給客戶端代碼。

這個問題與特定的實現無關,但我將其標記為正在使用的特定工具。 也許對某人的回答很有用。

首先,讓我解釋一下為什么使用實體框架(或另一個ORM工具)比使用存儲過程更優雅。

存儲過程是邪惡的 這就是為什么。 正如該鏈接詳細解釋的那樣,存儲過程傾向於作為第二個BL增長,因此難以維護。 當該列在多個存儲過程中使用時,重命名列這一簡單任務將成為一項艱巨的任務。 當您使用ORM工具時,Visual Studio將為您完成大部分工作。

話雖如此,但我卻獲得了實體框架的第二個優勢。 您可以使用自己喜歡的.net語言來組成查詢。 實體框架不會直接執行查詢。 您可以在此處控制查詢何時執行查詢。 執行此實體框架時,會將您的Linq語句編譯為完整的tsql語句,並針對數據庫運行該語句。 因此,絕對不需要獲取所有數據並遍歷每個記錄。

提示:將光標移到變量名上,ef將為您預覽將要編譯的TSQL語句。

那么您的Linq查詢應該如何? 我根據您的描述組成了一個測試數據庫,並為其創建了一個實體框架(ef6)模型,如下所示:

EF模型

至少在我正確理解您的問題的前提下,此Linq查詢將執行您想要的操作。

private IEnumerable<Document> GetDocumentsOfUser(Guid userId)
    {
        using (var db = new DocumentRepositoryEntities())
        {
            // Get owned repositories by the user
            var ownedRepositories = db.Repositories
                          .Where(r => r.Owner.UserId == userId);

            // Get all users of teams the user belongs to
            var userInOtherTeams =
                 db.Users.Where(u => u.UserId == userId)
                        .SelectMany(u => u.Teams)
                        .SelectMany(t => t.Users);

            // Get the public repositories owned by the teammembers
            var repositoriesOwnedByTeamMembers =
                userInOtherTeams.Where(u => u.Repositories.Any())
                                .SelectMany(u => u.Repositories)
                                .Where(r => !r.Private);

            // Combine (union) the 2 lists of repositories
            var allRepositories = ownedRepositories.Concat(
                                  repositoriesOwnedByTeamMembers);

            // Get all the documents from the selected repositories
            return allRepositories.SelectMany(r => r.Documents)
                                  .Distinct()
                                  .ToArray(); //query will be composed here!
        }
    }

請注意,在調用.ToArray()時,linq語句將被編譯為TSQL select語句。

根據您的描述,目標是找到用戶當前有權訪問的所有存儲庫,然后從每個存儲庫中檢索文檔。

如果這是我的實現,則需要向數據庫中添加一個接受當前用戶ID的存儲過程,然后將可訪問存儲庫列表收集到本地表變量中,然后從documents表中選擇文檔存儲庫所在的位置。可訪問的存儲庫列表。

DECLARE
  @Teams TABLE (TeamID UNIQUEIDENTIFIER NOT NULL PRIMARY KEY (TeamID))

DECLARE
  @Repositories TABLE (RepositoryID UNIQUEIDENTIFIER NOT NULL PRIMARY KEY (RepositoryID))

  /* Get the list of teams the user is a member of */
INSERT INTO @Teams
SELECT Teams.TeamID
  FROM Teams INNER JOIN TeamUsers ON Teams.ID = TeamUsers.TeamID
 WHERE TeamUsers.UserID = @UserID

  /* Get the list of repositories the user shares a team member with */
INSERT INTO @Repositories
SELECT RepositoryID
  FROM Repositories
 WHERE OwnerID = @UserID 
    OR (OwnerID IN (SELECT DISTINCT TeamUsers.UserID
                     FROM TeamUsers INNER JOIN @Teams ON TeamUsers.TeamID = @Teams.TeamID)
       AND IsShared = 1)

  /* Finally, retrieve the documents in the specified repositories */
SELECT Documents.* 
  FROM Documents INNER JOIN @Repositories ON Documents.RepositoryID = @Repositories.RepositoryID

主管技術建議的答案是有效的,如果您的需求是一次性的,那么這很好,但理想情況下,您想要做的是在專用層中以外部化方式實現授權要求。 這樣做的原因包括:

  • 易於維護分離的架構
  • 您可以不修改應用程序和/或數據庫就更新授權
  • 您不需要SQL /存儲過程知識
  • 您可以更輕松地報告在什么地方應用了什么授權:如果審核員喘口氣,這一點很重要。

要實現外部授權 (有關此主題的Gartner報告 ,請參見此處),您需要考慮基於屬性的訪問控制(ABAC- 有關NIST關於ABAC的報告,請參見此處 )和可擴展訪問控制標記語言(XACML)- 更多信息此處 )作為實施ABAC的一種方式。

如果遵循ABAC方法,您將獲得:

  • 具有以下概念的干凈,分離的架構
    • 位於應用程序和數據庫之間的強制執行點或攔截器(如果ABAC應用於數據庫)
    • 授權決策引擎,該決策引擎將做出決策,並將生成一個過濾器語句(對於SQL數據庫,是WHERE子句),強制執行點將附加到原始SQL語句中
  • 一個基於策略和基於屬性的授權模型,通過該模型,您可以在易於理解的語句中編寫授權需求,而不是過程,PL-SQL或其他SQL構件。 示例包括:
    • *用戶可以編輯自己擁有的文檔
    • 如果用戶團隊==文檔團隊,則用戶可以查看文檔
    • 當且僅當文件被標記為公開時,用戶才能查看另一個團隊的文件
    • 具有角色編輯器的用戶可以並且僅當文檔狀態為草稿*時才能編輯屬於其團隊的文檔

在上述示例中,用戶類型,資源類型(文檔),操作(查看,編輯),文檔團隊,用戶團隊和文檔可見性(私有或公共)都是屬性的示例。 屬性是生命線,ABAC的基礎。

ABAC可以輕松地幫助您實現從最簡單的要求到更高級的授權要求(例如可以在出口法規,合規性法規或其他業務規則中找到)。

這種方法的一個好處是它並不特定於數據庫。 您可以將相同的原理和策略應用於本地開發的應用程序,API,Web服務等。 這就是我所謂的外部授權的任何深度架構/方法。 下圖很好地總結了它:

任意深度的架構和外部授權

PDP是您的集中式授權引擎。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM