3

悪意のあるデータの変更を防ぐためのアイデアを探しています:userAはuserBに属するデータを操作(編集または削除)します。クライアント上にエンティティを作成しているので、それら(または少なくとも一部)を認証されたユーザーに割り当てる必要があります。

例えば:

var newItem = ds.createNewItem();
newItem.OwnerId(22); //this is the problem that I see.    
newItem.Name("New Item");
newItem.Description("I just changed your item!");
... //and so on
ds.saveChanges();

APIを呼び出すユーザーのIDがわかっているとすると、SaveChangesこのユーザーに対してエンティティ(新規または変更済み)をどのように検証しますか?

頭に浮かぶ最初の考えは、エンティティプロパティをサブクラス化EFContextProviderし、オーバーライドして、ユーザーのIDと照合することです。例えば:BeforeSaveEntityOwnerId

if (entityInfo.Entity.GetType() == typeof(Item)
    && (entityInfo.EntityState == EntityState.Added 
    || entityInfo.EntityState == EntityState.Modified)
    && ((Item)entityInfo.Entity).OwnerId != _currentUserId) {
    return false
    ... //and so on

このアプローチを使用する場合_currentUserId、新しいEFContextProviderクラスのコンストラクターで確立することは意味がありますか?

この問題に取り組むためのアイデアまたはおそらくより良い方法はありますか?

4

1 に答える 1

5

あなたは正しい方向に進んでいると思います。私はこれを自分でうなずいていて、ほとんど同じ道を進んできました。

認証を処理し、利用可能なものがあると仮定しましょうIPrincipal。認証されたユーザーのためにを隠しておくことができるカスタムIIdentityもあります(それを呼び出します)。AppIdentityUserId

Web Apiの基本クラスは、そのプロパティを介してApiControllerアンビエントを利用できるようにします。これをカスタムBreezeWebApiコントローラーで活用します。これは次のように始まります。IPrincipalUser

[承認]
[JsonFormatter、ODataActionFilter]
パブリッククラスBreezeApiController:ApiController
{{
    プライベート読み取り専用AppContextProvider_context;

    public BreezeApiController(){
        //'User'IPrincipalをコンテキストctorに渡します
        _context = new AppContextProvider(User);
    }

    ..。

    //クエリアクションメソッドの1つ
    [HttpGet]
    public IQueryable <Foo> Foos(){
        _context.Foosを返します
    }

    ..。

あなたの習慣EFContextProviderはこのように始まるかもしれません:

パブリッククラスAppContextProvider:EFContextProvider <AppDbContext>
{{
    public AppContextProvider(IPrincipal user)
    {{
        UserId =((AppIdentity)user.Identity).UserId;
    }

    public int UserId {get; プライベートセット; }
    ..。

ここで、UserBのエンティティがUserAに表示されないようにする必要があります。したがって、すべての人が戸外Fooに出ることを許可する代わりに、カスタムEFContextProviderはそれに応じてフィルタリングすることができます。

   public DbQuery Foos
   {{
       得る
       {{
           //ここで、「コンテキスト」はEFDbContextです
           return(DbQuery)Context.Foos
               .Where(f => f.UserId == UserId);
       }
   }

コントローラを振り返ると、そのFoosGETアクションメソッドがフィルタに気付かないことがわかります...当然のことです。コントローラを軽量化し、ビジネスロジックをカスタムEFContextProviderとそのヘルパーに移行する必要があります。

最後に、非常に単純化された汎用BeforeSaveEntityは次のようになります。

private bool BeforeSaveEntity(EntityInfo info)
{{
    var entity = info.Entity;
    if(info.EntityState == EntityState.Added)
    {{
        entity.UserId = UserId;
        trueを返します。
    }
    UserId ==entity.UserId||を返します throwCannotSaveEntityForThisUser();
}

..。

private bool throwCannotSaveEntityForThisUser()
{{
    new SecurityException( "Unauthorized user");をスローします。
}

UserIdサーバー上のカスタムコンテキストプロバイダーが、追加されたエンティティの設定を担当していることに注意してください。とにかく、クライアントがそうすることを信頼しません。UserIdそしてもちろん、変更および削除されたエンティティの検証を担当します。

お役に立てれば。これは単なるスケッチであることを忘れないでください。実際の取引はより洗練され、ヘルパーにリファクタリングされます。

于 2012-11-28T09:37:29.850 に答える