2012-02-17 67 views
2

在MVC 3中,我試圖弄清楚如何正確應用角色和基於用戶的安全(並遵循最佳實踐)到我的某個視圖。我有一個觀點,列出任何給定的「成員」(又名用戶)的詳細信息。我希望所有會員都能查看其他會員的詳細信息,但如果會員查看他們自己的詳細信息,我希望他們能夠編輯自己的詳細信息。此外,網站管理員應該能夠編輯任何成員的詳細信息。將MVC基於用戶和基於角色的授權應用於查看和操作

供您參考,我的網站配置如下:

  • 我(使用或重寫的SqlMembershipProvider ),這是非常簡單,使用窗體身份驗證創建了自己的認證供應商。
  • 我覆蓋了默認的RoleProvider來爲IsUserInRole和GetRolesForUser實現我自己的方法。這兩種方法工作正常。
  • 我所有的視圖都使用從我的具體實體映射的「拼合」視圖模型。
  • 我的詳細視圖用於均爲顯示信息編輯信息。使用一個標誌(稱爲IsInEditMode)(並傳遞到一個自定義HtmlHelper)來確定是否僅顯示數據或提供編輯器字段。我想保留這個單一的觀點。

這是我的具體要求。我列出他們都在這個問題上,我認爲正確的答案會/應解決所有這些問題(讓我知道,如果這是不正確的):

  1. 成員應該能夠查看任何其他成員的詳細信息。
  2. 成員應該能夠編輯自己的詳細,但其細節的某些方面應當只能由站點管理員可編輯的(例如狀態批准或臨時的
  3. 成員屬於「站點管理員「角色可以編輯一切。
  4. 詳細信息視圖中的「編輯」按鈕只需根據成員的角色(作爲站點管理員)或用他們的登錄憑證驗證用戶標識/名稱來顯示。
  5. 控制器HttpPost編輯操作需要驗證用戶是否被批准編輯。我知道我可以用[Authorize(Roles = "Site Administrator")]這樣的角色修飾動作,但我不知道如何實現OR UserBeingEdited == LoggedInUser屬性。
  6. 此外,我想防止惡意編輯,如用戶「擺弄」返回的用戶ID值以及XSS和CSRF攻擊。

下面是控制器和視圖的適用代碼(沒有任何安全性)。任何建議表示讚賞!

MemberController.cs編輯動作sippet:

[HttpPost] 
[ValidateAntiForgeryToken] 
//TODO: Find out how to allow only "Site Administrator" roles OR the logged in user to edit their own information 
public ActionResult Edit(MemberDetailViewModel memberDetailViewModel) 
{ 
    if(ModelState.IsValid) 
    { 
    //TODO: Find out how to prevent member ID tampering (including XSS and CSRF attacks) 
    var updatedMember = _memberServices.Find(memberDetailViewModel.MemberId); 
    Mapper.Map(memberDetailViewModel, updatedMember); 
    _memberRepository.InsertOrUpdate(updatedMember); 
    return RedirectToAction("Detail", new {id = memberDetailViewModel.MemberId}); 
    } 
    else 
    { 
    return View("Detail", _memberQueries.GetMemberDetailViewModel(memberDetailViewModel.MemberId, isInEditMode:true)); 
    } 
} 

會員詳細信息。CSHTML查看(只有相關部分包括):

@model MyApp.Web.Areas.Members.Models.MemberDetailViewModel 
@using (Html.BeginForm("Edit", "Member", FormMethod.Post, new { id = "memberDetailForm", enctype = "multipart/form-data" })) 
{ 
    <fieldset id="pageTitle"> 
    <h2> 
     <!-- TODO: Only allow editing by "Site Administrators" or the verified logged in user --> 
     @if (Model.IsInEditMode) 
     { 
     @:Editing @Model.FirstName @Model.LastName 
     <a class="button" href="@Url.Action("Detail", new { id = @Model.MemberId })">Cancel</a> 
     <input class="button" type="submit" value="Save" /> 
     @Html.HiddenFor(x => Model.MemberId) 
     @Html.AntiForgeryToken() 
     } 
     else 
     { 
     @:Details for @Model.FirstName @Model.LastName 
     <a class="button" href="@Url.Action("Edit", new { id = @Model.MemberId })">Edit</a> 
     } 
    </h2> 
    </fieldset> 
    <fieldset> 
     <legend>Basic Information</legend> 
     <table> 
     <tr> 
      <td class="label"> 
      First Name: 
      </td> 
      <td class="field"> 
      @Html.DisplayOrEditorFor(x => Model.FirstName, Model.IsInEditMode) 
      @Html.ValidationMessageFor(x => Model.FirstName) 
      </td> 
     </tr> 
     <!-- Other properties omitted --> 
     <tr> 
      <td class="label"> 
      Status: 
      </td> 
      <td class="field"> 
      <!-- TODO: This status field should only be editable by "Site Administrator", not the user --> 
      @Html.DisplayOrEditorDropDownListFor(x => Model.StatusId, Model.StatusList, Model.IsInEditMode) 
      </td> 
     </tr> 
     </table> 
    </fieldset> 
} 

如果需要更好地瞭解我的觀點,這是我DisplayOrEditorFor定製的HtmlHelper功能的示例:

public static MvcHtmlString DisplayOrEditorFor<TModel, TValue>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TValue>> expression, bool isInEditMode) 
{ 
    return isInEditMode ? System.Web.Mvc.Html.EditorExtensions.EditorFor(htmlHelper, expression) : System.Web.Mvc.Html.DisplayExtensions.DisplayFor(htmlHelper, expression); 
} 

回答

3

在最簡單的方法你大小寫僅當被編輯的用戶的id ==當前用戶的id或用戶是管理員時才設置IsInEditMode。

您不想使用通用授權屬性以外的任何內容,因爲所有註冊用戶都可以訪問該頁面,因此您不希望或需要頁面本身,字段和其他字段上的其他身份驗證字段由您的IsInEditMode布爾值來控制。

您還可以在「編輯」鏈接上進行測試,以查看它是當前用戶還是管理員,以及針對只有管理員可以編輯的字段的特殊測試。

所以,你會做這樣的事情:

@Html.DisplayOrEditorDropDownListFor(x => Model.StatusId, Model.StatusList, 
    Model.IsInEditMode && User.IsInRole("Administrator")) 

無論是在編輯模式將在控制器中設置。如果它是當前用戶或管理員,它將只允許EditMode設置爲true。

+0

謝謝。這就說得通了。兩個問題給你...什麼是最好的方法來驗證我從用戶cookie收到的信息是有效的(防止UserId值的擺弄),以及如何實現需求#6(XSS和CSRF攻擊)。我總是聽到永遠不會信任用戶提供的數據(包括表單和cookie值),那麼在我的控制器操作中驗證此信息的最佳做法是什麼? – bigmac 2012-02-17 22:06:16

+0

@bmccleary - 什麼cookie值?我給你的解決方案沒有包含任何與cookie相關的東西。 XSS通過編碼任何用戶提供的輸入來解決。 CSRF通過使用AntiForgeryToken幫手來解決。您必須確保編輯操作方法驗證用戶是管理員或當前用戶。你可以簡單地通過重定向來處理它們,如果它們不是,或者只是顯示即使它是編輯方法。 – 2012-02-18 03:37:01

+0

@bmccleary - 雖然這個解決方案有效,但我想知道這是否是正確的態度。通過此解決方案,與EditMode相關的代碼分佈在兩個位置(對於每個操作) - 在Controller和View中。一個更好的選擇,恕我直言,是把控制EditMode的代碼放在一個專門的類中,通過一些魔術將用戶引導到基於角色的正確的Controller操作。想一想,如果你的要求複雜化,你發送給HtmlHelper的條件會發生什麼。 – Ikaso 2012-10-14 07:48:38