В MVC 3 я пытаюсь выяснить, как правильно применять как ролевую, так и пользовательскую безопасность (и следуя рекомендациям) к одному из моих представлений.У меня есть представление, которое перечисляет детали для любого данного «члена» (он же пользователь).Я хочу, чтобы все участники могли просматривать детали любого другого участника, но если участник просматривает свои собственные данные, я хочу, чтобы они могли редактировать свои собственные данные.Кроме того, администратор сайта должен иметь возможность редактировать любые сведения об участниках.
Для справки, мой сайт настроен следующим образом:
- Я создал свой собственный поставщик аутентификации (не с использованием или переопределением SqlMembershipProvider), который очень прост и использует аутентификацию форм.
- Я переопределил RoleProvider по умолчанию для реализации моих собственных методов для IsUserInRole и GetRolesForUser.Оба метода работают нормально.
- Во всех моих представлениях используются "сплющенные" модели представления, которые сопоставляются с моими конкретными объектами.
- Представление My Detail используется для обоих отображения информации и редактирование информации.Флаг (называемый IsInEditMode) используется (и передается в пользовательский HtmlHelper), чтобы определить, следует ли просто отображать данные или предоставлять поле редактора.Я хотел бы сохранить это единственное представление.
Вот мои конкретные требования.Я перечисляю их всех в этом вопросе, так как считаю, что правильный ответ будет / должен решить все эти проблемы (дайте мне знать, если это неверно):
- Участники должны иметь возможность просматривать любые другиеподробности участника.
- Участники должны иметь возможность редактировать большинство своих собственных сведений, но некоторые аспекты их сведений должны редактироваться только администратором сайта (например, Status из утвержденных или предварительных)
- Участники, принадлежащие к роли «Администратор сайта», могут редактировать все.
- Кнопка «Изменить» в подробном представлении должна отображаться только в зависимости от роли участника(как администратор сайта) или проверка идентификатора / имени пользователя с их учетными данными.
- Для действия HttpPost Edit контроллера необходимо убедиться, что пользователь утвержден для редактирования.Я знаю, что могу украсить действие ролью, подобной
[Authorize(Roles = "Site Administrator")]
, но я не знаю, как реализовать атрибут OR UserBeingEdited == LoggedInUser
. - Кроме того, я хочу предотвратить такие злонамеренные изменения, как пользователь "возиться с возвращенным значением идентификатора пользователя, а также атаками 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));
}
}
Элемент Detail.cshtml View (включены только соответствующие части):
@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);
}