13

In my Controller before a Model is modified (updated or deleted) I am trying to verify that the User performing the action actually owns the object they are trying to modify.

I am currently doing this at the method level and it seems a bit redundant.

[HttpPost]
public ActionResult Edit(Notebook notebook)
{
    if (notebook.UserProfileId != WebSecurity.CurrentUserId) { return HttpNotFound(); }

    if (ModelState.IsValid)
    {
        db.Entry(notebook).State = EntityState.Modified;
        db.SaveChanges();
        return RedirectToAction("Index");
    }
    return View(notebook);
}

Is there a generic way of doing this that could be reusable across various models?

Is it possible to do this with an ActionFilter?

4

4 に答える 4

5

フィルター アプローチは次のようになります。

public class VerifyOwnership : IActionFilter
{
    public void OnActionExecuting(ActionExecutingContext filterContext)
    {
        foreach(var parameter in filterContext.ActionParameters)
        {
            var owned  = paramter.Value as IHaveAnOwner;
            if(owned != null)
            {                    
                if(owned.OwnerId != WebSecurity.CurrentUserId)
                {
                    // ... not found or access denied
                }
            }
        }
    }

    public void OnActionExecuted(ActionExecutedContext filterContext)
    {

    }
}

これは、ノートブックのようなモデルが特定のインターフェイスを実装していることを前提としています。

public interface IHaveAnOwner
{
    int OwnerId { get; set; }
}

Blowdart には、ユーザーが投稿の OwnerId を改ざんできるという良い点があります。彼らも自分の認証チケットを改ざんできると確信していますが、他のユーザーのチケットを知っていて、両方を改ざんして、ID を別のユーザーと一致させる必要があると思います。

于 2012-09-21T20:08:07.767 に答える
3

フィルタは問題ないアプローチのように聞こえますが、多少制限があります。次のようなフィルターがあればいいのですが。

[RequireOwnership<Notebook>(n => n.UserProfileId)]

...ただしAttributes、許可されるデータ型には制限があり、ジェネリックも許可されていないと思います。したがって[RequireOwnership]、リフレクションを使用してモデルプロパティを検査することで機能する属性を設定することも、代わりにカスタムバリデーターを作成してモデルを次のようにすることもできます。

public class Notebook
{
    [MatchesCurrentUserId]
    public int UserProfileId { get; set; }
}

その後、ModelState.IsValidチェックで十分です。

編集:

別の選択肢が思い浮かびました。モデルの属性と組み合わせてフィルターを使用できます(である必要はありませんValidationAttribute)。[MatchesCurrentUserId]フィルタは、現在のユーザーIDと比較して、リクエストモデルを検査し、でプロパティを確認できます。

于 2012-09-19T20:14:11.930 に答える
3

あなたが持っているものには1つの問題があります-セキュリティチェックを実行するためにユーザー入力に依存しています。

あなたのコードを検討してください

if (notebook.UserProfileId != WebSecurity.CurrentUserId)

ノートブックはモデル バインドから来ています。したがって、UserProfileId はモデル バインディングから取得されました。たとえば、Firefox の TamperData を使用して、非表示の UserProfileId の値を自分のログインに一致するように変更し、その場を離れます。

私が(コントローラーではなくサービスで)やっていることは、渡された一意のIDに基づいてデータベースからレコードをプルバックし(たとえば、Edit/2は2を使用します)、User.Identityをチェックする投稿です。返されたデータベース レコードにある現在の所有者フィールドに対する名前 (つまり、渡された ID パラメーター)。

私はデータベース(リポジトリなど)から引き戻すため、属性はこれには機能しません。とにかく、属性のアプローチで十分に一般的であるかどうかはわかりません。

于 2012-09-20T19:18:43.433 に答える
1

私が過去にこのようなことをしたとき、それは本当にそれほど良くはありませんでした. 私たちのプロジェクトでは、Notebookオブジェクトを受け取り、現在ログインしているユーザーと照合するメソッドがあります。

このメソッドをさまざまなオブジェクト タイプすべてでオーバーロードし、一貫したメソッドを使用してアクセスをチェックすることができます。申し訳ありませんが、それが私が知っている最善の方法です。

[HttpPost]
public ActionResult Edit(Notebook notebook)
{
    if(!SessionUser.LoggedInUser.CheckAccess(notebook))
        return HttpNotFound();

    //Other code...
}

PSSessionUserは基本的に、その時点でログインしているユーザーを管理するためだけに作成したカスタム クラスです。似たようなものを書くこともできますが、デフォルトで .NET にあるとは思わないでください。

于 2012-09-19T20:16:17.327 に答える