2017-06-27 16 views
0

必須有這樣一個普通的問題,簡單的解決辦法,所以我很抱歉,前期爲我的無知:如何授權用戶只能看到他自己的記錄用asp.net身份2.0

我有一個多用戶Web應用程序(與EF6的Asp.net MVC5)即是允許用戶查看和/或修改存儲在幾個相關表格(公司,Csearch,候選人)中的相關數據。 (更多細節見下文)。他們不應該看到任何其他數據(例如通過篡改URL)。

我使用Asp.net Identity 2.0進行身份驗證,並希望將其用於提及的授權。用戶數據存儲在標準的AspNetUser表中。我僅對Identity和我的業務表使用一個上下文。

我想我必須使用角色或可能聲明來解決這個問題,但我找不到任何指導如何做到這一點。任何人都可以將我指向正確的方向嗎?

我目前通過向CompanyController添加LINQ條件解決了這個問題(對於公司模型),但這似乎不是解決問題的非常安全和正確的方法。

public ActionResult Index(int? id, int? csearchid) 
     { 
      var companies = db.Companies 
       .OrderBy(i => i.CompanyName) 
       .Where(t => t.UserName == User.Identity.Name); 
     return View(companies); 

我的DataModel很簡單,我是有腳手架使用Visual Studio 2017年 通過第一我已經建立了一個關係型數據模型是大致如下EF6代碼:

,公司可以有多個搜索(一至許多)。 每個搜索可以有多個候選人(一對多)。 公司可以有多個USERS登錄。 用戶保存在由ASP.Net Identity生成的AspNetUsers表中。

我公司的模型如下所示:

public class Company 
{ 
    public int CompanyID { get; set; } 

    // Link naar de Userid in Identity: AspNetUsers.Id 
    [Display(Name = "Username")] 
    public string UserName { get; set; }   
    public string CompanyName { get; set;} 
    public string CompanyContactName { get; set; } 
    [DataType(DataType.EmailAddress)]   
    public string CompanyEmail { get; set; } 
    public string CompanyPhone { get; set; }   

    [Timestamp] 
    public byte[] RowVersion { get; set; } 

    //One to Many Navigatie links 
    public virtual ICollection<Csearch> Csearches { get; set; } 
+0

你所做的是其中的一部分。您可能希望更具體的訪問權限(包含角色)使用具有角色或自定義屬性的「授權」屬性。 –

回答

0

這很簡單真的。用您提供的示例公司來說明。請注意,您應該使用UserId加入而不是UserName,因爲UserName可以更改,但UserId將始終是唯一的。)

而不是在公司表中具有用戶名,您需要將其更改爲UserId。然後,您可以使用UserId上的Company表加入AspNetUsers表。

例如(我更喜歡使用的查詢語法而不是流利的語法):

var companies = from c in db.Companies join u in db.AspNetUsers 
       on c.UserId equals u.UserId 
       orderby c.CompanyName 
       where u.UserName = User.Identity.Name 
       select c; 

如果需要用戶名和,然後包括在您的選擇

select new { Company = c, User = u.UserName }; 

然而如果您希望每個公司有多個用戶,則此模型不起作用。您需要將CompanyId添加到用戶表(假設用戶不能是多個公司的成員),或者如果用戶可以成爲多個公司的成員,則創建多對多連接。

因此,不要將用戶鏈接到公司,而是將公司鏈接到用戶。您目前的模型只允許每個公司一個用戶。

我在這裏看到錯誤的另一件事是在您的實體對象中使用DisplayName。這似乎表明你在你的MVC視圖中使用實體,你不應該這樣做。你應該創建一個單獨的ViewModel。

這是應該的樣子,每家公司的多個用戶:

public class Company 
{ 
    public int CompanyID { get; set; } 

    // Link naar de Userid in Identity: AspNetUsers.Id 
    // [Display(Name = "Username")] <-- Get rid of these 
    // public string UserName { get; set; } <-- get rid of these 
... 
} 

public class ApplicationUser : IdentityUser 
{ 
    public int CompanyId { get; set; } 
} 

然後改變你的查詢:

var companies = from c in db.Companies join u in db.AspNetUsers 
      on c.CompanyId equals u.CompanyId // <-- Change to this 
      orderby c.CompanyName 
      where u.UserName = User.Identity.Name 
      select c; 
+0

謝謝Erik!這似乎確實是最簡單的方法。你有沒有可能知道這是否也是一個安全的解決方案? –

+0

我收到一個錯誤,'ApplicationDbContext不包含AspNetUsers的定義'....我嘗試在上下文中添加一個DbSet,但是這並沒有解決任何問題。建議? –

+0

謝謝埃裏克。它適用於特定的視圖,但我仍然可以訪問其他視圖上的所有數據。作爲一個例子,當我打開Details-view時,我仍然可以看到未經授權的公司數據。 (.../Company/Details/2)直接在瀏覽器命令行中輸入。 –

1

一旦用戶被識別,可以確保用戶可以只能訪問自己的數據。你不能使用角色,因爲那隻會定義訪問級別。但你可以使用聲明。

開箱即用有關注點分離。保持這種分離。您不打算直接查詢Identity表。爲此使用userManager。另外永不使用Identity對象作爲ViewModel。你可能暴露超過你的意思。如果你保持這種分離,你會發現它實際上更容易。

身份上下文包含識別用戶的所有數據,業務上下文包含所有業務信息,包括用戶信息。您可能認爲這是多餘的,但登錄用戶與業務用戶沒有什麼共同之處。登錄電子郵件地址可能與business.user.emailaddress不同(兩種情況下電子郵件地址的含義是什麼?)。還要考慮讓用戶無法登錄的可能性。

作爲一個經驗法則總是考慮,如果信息是身份或業務的一部分的一部分。

你什麼時候需要ApplicationUser?僅限當前用戶或管理用戶時。查詢用戶時,請始終使用business.user。因爲你需要的所有信息應該在那裏可用。

對於當前用戶,添加您所需信息的聲明。聲明的優點是,您不必在每次調用時查詢數據庫以檢索此信息,例如相應的UserId和(顯示)用戶名。

如何添加索賠

可以,而不必延長ApplicationUser類,通過增加一行到AspNetUserClaims表中添加要求給用戶。例如:

userManager.AddClaim(id, new Claim("UserId", UserId)); 

登錄時,索賠將自動添加到ClaimsIdentity。

您還可以添加擴展ApplicationUser的性能要求:

public class ApplicationUser : IdentityUser 
{ 
    public int UserId { get; set; } 

    public string DisplayUserName { get; set; } 

    public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager) 
    { 
     // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType 
     var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie); 

     // Add custom user claims here 
     userIdentity.AddClaim(new Claim("UserId", UserId)); 
     userIdentity.AddClaim(new Claim("DisplayUserName", DisplayUserName)); 

     return userIdentity; 
    } 
} 

如何閱讀要求

在控制器,你可以這樣寫有代碼的要求:

var user = (System.Security.Claims.ClaimsIdentity)User.Identity; 
var userId = user.FindFirstValue("UserId"); 

您可以在查詢中使用userId來過濾當前用戶的數據,甚至可以使用business.users作爲o只需輸入檢索數據。 Like db.Users(u => u.Id == userId).Companies.ToList();

請注意,代碼僅僅是一個例子。我沒有測試全部。這只是給你一個想法。如果事情不清楚,請告訴我。

+0

感謝您的廣泛答覆。我將開始實施它。只要我成功了(這可能需要一段時間:)),我絕對會讓你知道。 –

+0

如果你創建一個新的Asp.Net Mvc項目,你將不必實現它。因爲它是模板的一部分。您只需添加聲明並將用戶表添加到業務環境中即可。 –

相關問題