在MVC 3中,我試圖弄清楚如何正確應用角色和基於用戶的安全(並遵循最佳實踐)到我的某個視圖。我有一個觀點,列出任何給定的「成員」(又名用戶)的詳細信息。我希望所有會員都能查看其他會員的詳細信息,但如果會員查看他們自己的詳細信息,我希望他們能夠編輯自己的詳細信息。此外,網站管理員應該能夠編輯任何成員的詳細信息。將MVC基於用戶和基於角色的授權應用於查看和操作
供您參考,我的網站配置如下:
- 我(使用或重寫的SqlMembershipProvider 不),這是非常簡單,使用窗體身份驗證創建了自己的認證供應商。
- 我覆蓋了默認的RoleProvider來爲IsUserInRole和GetRolesForUser實現我自己的方法。這兩種方法工作正常。
- 我所有的視圖都使用從我的具體實體映射的「拼合」視圖模型。
- 我的詳細視圖用於均爲顯示信息和編輯信息。使用一個標誌(稱爲IsInEditMode)(並傳遞到一個自定義HtmlHelper)來確定是否僅顯示數據或提供編輯器字段。我想保留這個單一的觀點。
這是我的具體要求。我列出他們都在這個問題上,我認爲正確的答案會/應解決所有這些問題(讓我知道,如果這是不正確的):
- 成員應該能夠查看任何其他成員的詳細信息。
- 成員應該能夠編輯自己的詳細最,但其細節的某些方面應當只能由站點管理員可編輯的(例如狀態批准或臨時的)
- 成員屬於「站點管理員「角色可以編輯一切。
- 詳細信息視圖中的「編輯」按鈕只需根據成員的角色(作爲站點管理員)或用他們的登錄憑證驗證用戶標識/名稱來顯示。
- 控制器HttpPost編輯操作需要驗證用戶是否被批准編輯。我知道我可以用
[Authorize(Roles = "Site Administrator")]
這樣的角色修飾動作,但我不知道如何實現OR UserBeingEdited == LoggedInUser
屬性。 - 此外,我想防止惡意編輯,如用戶「擺弄」返回的用戶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);
}
謝謝。這就說得通了。兩個問題給你...什麼是最好的方法來驗證我從用戶cookie收到的信息是有效的(防止UserId值的擺弄),以及如何實現需求#6(XSS和CSRF攻擊)。我總是聽到永遠不會信任用戶提供的數據(包括表單和cookie值),那麼在我的控制器操作中驗證此信息的最佳做法是什麼? – bigmac 2012-02-17 22:06:16
@bmccleary - 什麼cookie值?我給你的解決方案沒有包含任何與cookie相關的東西。 XSS通過編碼任何用戶提供的輸入來解決。 CSRF通過使用AntiForgeryToken幫手來解決。您必須確保編輯操作方法驗證用戶是管理員或當前用戶。你可以簡單地通過重定向來處理它們,如果它們不是,或者只是顯示即使它是編輯方法。 – 2012-02-18 03:37:01
@bmccleary - 雖然這個解決方案有效,但我想知道這是否是正確的態度。通過此解決方案,與EditMode相關的代碼分佈在兩個位置(對於每個操作) - 在Controller和View中。一個更好的選擇,恕我直言,是把控制EditMode的代碼放在一個專門的類中,通過一些魔術將用戶引導到基於角色的正確的Controller操作。想一想,如果你的要求複雜化,你發送給HtmlHelper的條件會發生什麼。 – Ikaso 2012-10-14 07:48:38