0

如果 move.UserId 不等于 currentUserId 则尝试构建异常然后重定向到操作,否则如果 move.UserId 不等于 currentUserId 返回视图。

请参阅此处的代码:

public ActionResult Details(int id)
    {
        MembershipUser currentUser = Membership.GetUser();
        Guid currentUserId = (Guid)currentUser.ProviderUserKey;
        Move move = db.Moves.Where(m => m.UserId == currentUserId)
            .FirstOrDefault();

            if (currentUser != null && currentUser.ProviderUserKey != null && currentUser.IsApproved)
            {
                if (move.UserId == currentUserId)
                {
                    return View(move);
                }
            }

        return RedirectToAction("Oops", new RouteValueDictionary(
 new { controller = "Account", action = "Oops", area = "", id = UrlParameter.Optional }));
    }

我想将它绑定到将带回 Move/(int) 的 url,这样如果用户将其修改为返回 move.UserId != currentUserId 的移动的 (int),那么它们也会重定向。目前可以修改Url来获取其他人的招式。

我的控制器

    public ViewResult Index()
    {
        if (User.Identity.IsAuthenticated)
        {
            MembershipUser currentUser = Membership.GetUser();
            Guid currentUserId = (Guid)currentUser.ProviderUserKey;
            if (currentUser != null && currentUser.ProviderUserKey != null && currentUser.IsApproved)
            {
                var results = db.Moves.Where(move => move.UserId == currentUserId)
                    .ToList();
                return View(results);
            }
        }
        return View(db.Moves.ToList());
    }

    [ClientValidation]
    public ActionResult Details(Move move)
    {
        return View(move);
    }

我的观点

@model MovinMyStuff.Domain.Entities.Move
@{
ViewBag.Title = "Details";
    }
<div>

    @Html.DisplayFor(model => model.StartCity),
    @Html.DisplayFor(model => model.StartState)
    @Html.DisplayFor(model => model.StartZip) -
    @Html.DisplayFor(model => model.EndCity),
    @Html.DisplayFor(model => model.EndState)
    @Html.DisplayFor(model => model.EndZip)
</div>
<fieldset>
    <div class="job-details">
    @Html.HiddenFor(model => model.MoveId)
    @Html.HiddenFor(model => model.UserId)
        <ul class="distance">
            <li>
                <div>
                    Distance</div>
            </li>
            <li>1,978.6 Miles</li>
        </ul>
        <ul class="address-wrapper">
            <li>
                <ul class="address from">
                    <li>
                        <div>
                            From</div>
                    </li>
                    <li><span>Address: </span>
                        @Html.DisplayFor(model => model.StartStreetNumber)
                        @Html.DisplayFor(model => model.StartStreetName)
                    </li>
    ...
    </fieldset>
4

2 回答 2

1

首先要测试的是 LINQ 查询是否返回了 Move。如果不是,则表示用户正在尝试显示不属于他的移动,因为在您的查询中,您有一个.Where子句仅限制当前用户移动。

现在你会得到一个 NullReferenceException。

所以:

[Authorize]
public ActionResult Details(int id)
{
    MembershipUser currentUser = Membership.GetUser();
    Guid currentUserId = (Guid)currentUser.ProviderUserKey;
    Move move = db.Moves.Where(m => m.UserId == currentUserId && m.MoveId == id).FirstOrDefault();
    if (!currentUser.IsApproved || move == null)
    {
        // the user is trying to display a move that doesn't belong to him =>
        // redirect him or throw a 403 HTTP exception
        return RedirectToAction("Oops", new RouteValueDictionary(new { controller = "Account", action = "Oops", area = "", id = UrlParameter.Optional }));
    }

    // at this stage we can grant access to the user because we know
    // that he is authenticated, he is approved and that the move he is
    // trying to consult belongs to him
    return View(move);
}

显然,如果您需要在许多控制器操作中重复此逻辑,则值得编写自定义 Authorize 属性:

[EnsureUserAllowedToConsultMove]
public ActionResult Details(Move move)
{
    // at this stage we can grant access to the user because we know
    // that he is authenticated, he is approved and that the move he is
    // trying to consult belongs to him
    return View(move);
}

下面是这个自定义 Authorize 属性的样子:

public class EnsureUserAllowedToConsultMoveAttribute : AuthorizeAttribute
{
    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        var authorized = base.AuthorizeCore(httpContext);
        if (!authorized)
        {
            return false;
        }

        if (!httpContext.Request.RequestContext.RouteData.Values.ContainsKey("id"))
        {
            return false;
        }

        var id = (string)httpContext.Request.RequestContext.RouteData.Values["id"];
        var currentUser = Membership.GetUser();
        var currentUserId = (Guid)currentUser.ProviderUserKey;
        return db.Moves.Any(m => m.UserId == currentUserId && m.MoveId == id);
    }

    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        var values = new RouteValueDictionary(new
        {
            controller = "account",
            action = "oops",
            area = ""
        });
        filterContext.Result = new RedirectToRouteResult(values);
    }
}

现在,您已经设法分离关注点并将授权逻辑外部化为自定义授权属性。您的控制器不再需要被此类代码污染。

于 2012-06-28T08:54:20.580 回答
0

对于此类工作,您应该使用 Authorize 过滤器。查看此以获取更多信息ASP.NET MVC 自定义授权

于 2012-06-28T08:51:52.553 回答