3

既存の製品を完全に書き直しています (PHP から C# に変更中です)。私たちが既存の製品で遭遇した問題の 1 つは認証の問題です。いつでもどこでも確認しないと、許可されていないものが表示されてしまいます。常にチェックされていることを確認するのに最適な場所はどこですか? データレイヤーはこれを行うのに最適な場所だと思いますが、他の提案は大歓迎です。

NHibernate を使用するため、エンティティを提供するクラスを作成しました。次のようになります。

class DataProvider {
    TEntity Get<TEntity>(int id) {
        return GetSession().Get<TEntity>(id);
    }

    IQueryable<TEntity> Query<TEntity>()
    {
        return GetSession().Query<TEntity>();
    }

    // ...
}

DataProvider.Get<Person>(1)これにより、を使用して LINQ クエリを呼び出したり実行したりできますfrom person in DataProvider.Query<Person>() select person。インターセプターを使用すると、ユーザーが権限を持っていない単一のオブジェクトへのアクセスを拒否できます (ただし、そのコードを に挿入することはおそらく可能ですDataProvider.Get)。LINQを使おうとすると面倒になる。100 万のエンティティを含むテーブルがあり、5 つのエンティティにしかアクセスできないとします。インターセプターを使用すると、テーブル全体が取得され、返された各エンティティがテストされますが、必要なエンティティは 5 つだけです。私が想像できる最善の方法は、カスタム SQL を注入して、取得するオブジェクトを NHibernate に伝え、他のすべてを無視することです。オブジェクトへのアクセス権があるかどうかを判断できるシステムは既に用意されています。それからクエリを作成する方法も知っていると仮定しましょう。

私は何を試しましたか?

  • インターセプター (遅すぎます。必要なオブジェクトが 5 つだけなのに、100 万個のオブジェクトを取得します)。
  • イベント (IPostLoadEvent は私が必要とするものに最も近いですが、遅すぎます)。
  • カスタム NhQueryable および DefaultQueryProvider。これにより例外がスローされます: " The constant for 'MyQueryable<Person>' is not supported"。これは、NHibernate の奥深くでキャストされているためだと思います。NHibernate がカスタム クエリ プロバイダまたはクエリ可能を許可するように設計されているとは思えません。
  • OnPrepareStatement インターセプター。これは信じられないほど醜いです。SQL を編集できますが、得られるのは文字列だけです。これは機能しますが、同じことを行うもっとエレガントな方法があることを願っています。

他のユーザーは認証コードをどのように処理しますか? 承認チェックの呼び出しを忘れないようにするにはどうすればよいでしょうか?

4

2 に答える 2

1

NHibernate フィルターを確認する必要があると思います。

Ayende による素敵なイントロ: http://ayende.com/blog/3993/nhibernate-filters

数年前、あなたと同様のシナリオで NH フィルターを使用することに成功しました。以下にフィルターのエッセンスを添付しました。この場合、アクセスを制御したいすべてのクラスは、基本クラス「SecuredObject」から継承されています。「フォルダ」には「ドキュメント」という概念もありました。ここでは文脈から外れていますが、おそらくいくつかのアイデアを得ることができます.

<filter name="GrantedSecuredObjectsOnly" condition=" ... Id IN (SELECT SecurityGrant.SecuredObjectId FROM SecurityGrant WHERE SecurityGrant.SecuredObjectConsumerId=:userId)) OR (Id IN (SELECT Document.Id FROM Document WHERE Document.FolderId IN (SELECT SecurityGrant.SecuredObjectId FROM SecurityGrant WHERE SecurityGrant.SecuredObjectConsumerId=:userId)) ... "/>

もちろん、userId は現在ログオンしているユーザー ID に設定されます。

于 2012-05-31T20:04:45.063 に答える
0

編集済み:私は何を考えていましたか!

私はあなたが authenticationId / EnteredById であなたのデータをスタンプしていると推測しています

var userId = ...; //your authentication id

from entity in context.Entities    
where context.Entities.Where(x => x.EnteredById == userId && x.Id == entity.Id)
select entity;

これでやるべきだと思う


var query = new AuthorisedDataQuery<Entity>();
var entities = _dataProvider.Get(query);

承認されたデータ クエリの実装を作成するのは非常に簡単です。


仕様を持つクエリ: 擬似コード

var userId = ... //authentication
var specification = PredicateBuilder.True<Entity>();
specification = PredicateBuilder.And(specification, x => x.EntityId == userId); //default: build from this
var additionalCriterias = ...;
specification = additionalCriterias == null || additionalCriterias.Length == 0 
                  ? specification 
                  : GetComposedSpecification(additionalCriterias);

var query = from entity in context.Entities
            join anyOtherEntity in context.AnyOtherEntity on entity.EntityId equals anyOtherEntity.Entity.EntityId
            where db.Context.Entities.Where(specification).Contains(entity.EntityId)
            select entity;

あなたが達成しようとしているのは、デフォルトからクエリ基準/仕様を構築することです

linkkit @ http://www.albahari.com/nutshell/predicatebuilder.aspx経由の述語ビルダー

于 2012-05-29T10:22:35.247 に答える