在MVC 3中,我试图弄清楚如何正确地(并遵循最佳实践)将基于角色和用户的安全性应用于我的一个观点。我有一个视图,列出任何给定的“成员”(aka用户)的详细信息。我希望所有成员能够查看任何其他成员的详细信息,但如果成员正在查看他们自己的详细信息,我希望他们能够编辑自己的详细信息。此外,站点管理员应该能够编辑任何成员详细信息。
供您参考,我的网站配置如下:
以下是我的具体要求。我在这个问题中列出了所有内容,因为我相信正确的答案会/应该解决所有这些问题(如果这是不正确的,请告诉我):
[Authorize(Roles = "Site Administrator")]
之类的角色来装饰动作,但我不知道如何实现OR UserBeingEdited == LoggedInUser
属性。以下是我的适用代码(没有应用任何安全性),用于控制器和视图。任何建议都表示赞赏!
MemberController.cs Edit Action 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));
}
}
会员详情.csh查看(仅包含相关部分):
@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);
}
答案 0 :(得分:3)
在您的情况下,最简单的解决方案是仅在编辑的用户的ID =当前用户的ID或用户是管理员时设置IsInEditMode。
您不希望使用除通用Authorize属性之外的任何内容,因为所有注册用户都可以访问该页面,因此您不希望或需要在页面本身上进行额外的auth,仅在字段和那些字段上由您的IsInEditMode布尔值控制。
您还可以在“编辑”链接上进行测试,看看它是当前用户还是管理员,以及只有管理员可以编辑的字段的特殊测试。
所以,你会做这样的事情:
@Html.DisplayOrEditorDropDownListFor(x => Model.StatusId, Model.StatusList,
Model.IsInEditMode && User.IsInRole("Administrator"))
是否处于编辑模式将在控制器中设置。它只允许EditMode设置为true,如果它是当前用户或admin。