2016-04-14 39 views
1

我們正在使用WebAPI/OData項目爲我們的應用程序公開數據層。用於訪問控制的Odata控制器中的其他篩選

的.NET Framework 4.6.1
System.Web.OData,版本= 5.9.0.0

我們有不同的數據集(外科醫生,患者等)幾的OData控制器。如果我正在嘗試搜索患者,我會發出一個OData查詢,如下所示,以獲得符合我所需標準的患者列表。

http://localhost/MyService/Patients?$filter=contains($it/Name,」Joe」) 

問題是我可能不被允許查看所有的患者。由於RESTful API將在外部暴露,我不能依靠客戶端通過操縱url來強制執行安全要求。

如果我使用聲明授予用戶對特定患者的訪問權限,我可以切實保護對個人用戶的訪問權限,但搜索匹配用戶列表根本無效。

http://localhost/MyService/Patients(Id) 

如果我嘗試解決這個問題,並通過擁有患者的實體訪問相同類型的問題發生在下一個更高級別。換句話說,如果外科醫生擁有患者,那麼我如何獲得我可以使用的外科醫生名單?

有沒有辦法向OData構建的查詢注入一些額外的條件來強制訪問控制?

回答

1

這是對患者的OData控制器

public class PatientsController : BaseODataController<Patient> 
{ 
    public override IQueryable<Patient> Get() 
    { 
     return base.Get(); 
    } 
    ... 
} 

它返回IQueryable的GET方法<患者> ...

,我們需要做的只是添加訪問控制過濾添加在附加謂詞中...例如:

public override IQueryable<Patient> Get() 
{ 
    var qry = base.Get(); 
    return qry.Where(itm => itm.Name.FirstName.Contains("R")); 
} 

當控制器基礎設施枚舉的IQueryable <Ť>它評估整個工作單元並且生成最終的查詢。

如果我運行跟蹤對數據庫,並給它一個更復雜的OData查詢像

http://localhost/MyService/Patients?$filter=Surgeries/any(d:d/PreOpDataComplete%20eq%20true). 

(換句話說找到外科手術中的Pr​​eOpDataComplete標誌爲真),我會看到執行下面的查詢。

exec sp_executesql N'SELECT 
        [Project1].[C1] AS [C1], 
        [Project1].[Id] AS [Id], 
        [Project1].[Name_FirstName] AS [Name_FirstName], 
        [Project1].[Name_LastName] AS [Name_LastName], 
        [Project1].[Gender] AS [Gender], 
        [Project1].[BirthDate] AS [BirthDate], 
        [Project1].[MedicalRecordId] AS [MedicalRecordId], 
        [Project1].[Surgeon_Id] AS [Surgeon_Id] 
        FROM (SELECT 
            [Extent1].[Id] AS [Id], 
            [Extent1].[Name_FirstName] AS [Name_FirstName], 
            [Extent1].[Name_LastName] AS [Name_LastName], 
            [Extent1].[Gender] AS [Gender], 
            [Extent1].[BirthDate] AS [BirthDate], 
            [Extent1].[MedicalRecordId] AS [MedicalRecordId], 
            [Extent1].[Surgeon_Id] AS [Surgeon_Id], 
            1 AS [C1] 
            FROM [dbo].[Patient] AS [Extent1] 
            WHERE [Extent1].[Name_FirstName] LIKE N''%R%'' 
       )  AS [Project1] 
        WHERE  EXISTS (SELECT 
            1 AS [C1] 
            FROM [dbo].[Surgery] AS [Extent2] 
            WHERE ([Project1].[Id] = [Extent2].[Patient_Id]) AND ([Extent2].[PreOpDataComplete] = @p__linq__0) 
       )',N'@p__linq__0 bit',@p__linq__0=1 

我得到預期的結果

{ 
    "@odata.context":"http://localhost/MyService/$metadata#Patients", 
    "value":[{ 
     "Name":{ 
      "FirstName":"Ronn", 
      "LastName":"Black" 
     }, 
     "Gender":"M", 
     "BirthDate":"1917-02-02T00:00:00-08:00", 
     "MedicalRecordId":"MRN 0001", 
     "Id":"8bf6dcc4-3f00-4a40-980c-ceb13f8f5360" 
    }] 
} 

如果我假設一個簡單的安全模型,其中外科醫生擁有自己的病人,和我有我允許外科醫生ID列表訪問索賠。我想有一個看起來是這樣的一個外科醫生實體:

public partial class Surgeon : IBaseEntity 
{ 
    [Key] 
    public Guid Id { get; set; } 
    public virtual ICollection<Patient> Patients { get; set; } 
    . . . 
} 

現在,如果我提出以下修改我可以限制任何搜索,只是我被允許看到病人:

public override IQueryable<Patient> Get() 
{ 
    //IQueriable from the OData Selection 
    var qry = base.Get(); 
  
    //Enforce Access Security 
    var accessList = {get list of authorized surgeon id's from claims}; 
    var finalQry = uow.Surgeons 
        .Where(s => accessList.Contains(s.Id))  //Restrict to Surgeons I'm allowed to see 
        .SelectMany(surgeon => surgeon.Patients)  //All the patients I'm allowed to see (Left) 
        .Join(qry,                              //Join to Query (Right) 
            allowedPatients => allowedPatients.Id, //Key for Left 
            qryPatients => qryPatients.Id,         //Key for Right 
            (allowedPatients, qryPatients) =>      //Iterate through Matches 
            qryPatients);                          //Return the Matches from Right 
  
    return finalQry; 
}