应用基于MVC用户和基于角色的授权查看和操作

时间:2012-02-17 17:33:47

标签: asp.net-mvc authorization

在MVC 3中,我试图弄清楚如何正确地(并遵循最佳实践)将基于角色和用户的安全性应用于我的一个观点。我有一个视图,列出任何给定的“成员”(aka用户)的详细信息。我希望所有成员能够查看任何其他成员的详细信息,但如果成员正在查看他们自己的详细信息,我希望他们能够编辑自己的详细信息。此外,站点管理员应该能够编辑任何成员详细信息。

供您参考,我的网站配置如下:

  • 我创建了自己的身份验证提供程序(使用或覆盖SqlMembershipProvider),这非常简单并使用表单身份验证。
  • 我覆盖默认的RoleProvider,为IsUserInRole和GetRolesForUser实现我自己的方法。这两种方法都运行良好。
  • 我的所有观点都使用从我的具体实体映射的“扁平”视图模型。
  • 我的详细信息视图用于两者显示信息编辑信息。使用标志(称为IsInEditMode)(并传递到自定义HtmlHelper中)以确定是否仅显示数据或提供编辑器字段。我想保留这个单一的观点。

以下是我的具体要求。我在这个问题中列出了所有内容,因为我相信正确的答案会/应该解决所有这些问题(如果这是不正确的,请告诉我):

  1. 会员应该能够查看任何其他会员的详细信息。
  2. 会员应该能够编辑大多数自己的详细信息,但其细节的某些方面只能由网站管理员编辑(例如,状态已批准或临时)
  3. 属于“站点管理员”角色的成员可以编辑所有内容。
  4. 详细视图中的“编辑”按钮只需根据成员的角色(作为站点管理员)或使用其登录凭据验证用户ID /名称来显示。
  5. 控制器HttpPost Edit操作需要验证用户是否被批准编辑。我知道我可以用[Authorize(Roles = "Site Administrator")]之类的角色来装饰动作,但我不知道如何实现OR UserBeingEdited == LoggedInUser属性。
  6. 此外,我想防止恶意编辑,例如用户“摆弄”返回的用户ID值以及XSS和CSRF攻击。
  7. 以下是我的适用代码(没有应用任何安全性),用于控制器和视图。任何建议都表示赞赏!

    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);
    }
    

1 个答案:

答案 0 :(得分:3)

在您的情况下,最简单的解决方案是仅在编辑的用户的ID =当前用户的ID或用户是管理员时设置IsInEditMode。

您不希望使用除通用Authorize属性之外的任何内容,因为所有注册用户都可以访问该页面,因此您不希望或需要在页面本身上进行额外的auth,仅在字段和那些字段上由您的IsInEditMode布尔值控制。

您还可以在“编辑”链接上进行测试,看看它是当前用户还是管理员,以及只有管理员可以编辑的字段的特殊测试。

所以,你会做这样的事情:

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

是否处于编辑模式将在控制器中设置。它只允许EditMode设置为true,如果它是当前用户或admin。