2012-01-07 12 views
4

私は3つのテーブル:the User table, the Records table and the UserRecords tableを持っています。linq-to-sqlの照会権限を確保する

列がそうです:

UserTable 
UserID | OtherUserDataFields 

RecordsTable 
RecordID | OtherRecordDataFields 

UserRecords 
UserID | RecordID 

UserRecordsテーブルは、ユーザーがどのレコードで権限を持っていると言われます。私は2つのパラメータを受け取ることによってRecordsTableを更新する関数を持っています:レコードTheRecord(RecordIDフィールドを含む)とUserID。

ユーザーは、このようなそのレコードに許可されている場合、私は、パラメータやテストで供給されるレコードIDを持つレコードを取得するためにデータコンテキストMYDCでクエリを書いている:

var RecordToUpdate = (
    from r in MyDC.RecordsTable 
    from u in MyDC.UserRecords 
    where r.RecordID == TheRecord.RecordID && TheRecord.RecordID == u.RecordID 
    where u.UserID == TheUserID 
    select r).SingleOrDefault(); 

は、この私が保証されますユーザに許可されたレコードだけがフェッチされるでしょうか?私は、ユーザーが許可されていないレコードを悪意を持って送信し、これらの不正なレコードを変更するケースを避けたいと考えています。

ご協力いただきありがとうございます。

+0

'&& u.UserID = TheUserID'は' = 'が欠けています。今は割り当てです – Nuffin

+0

@Tobias:はい、ちょうどタイプミスです。ありがとう。 – frenchie

+0

'UserRecords'テーブルに外部キーが含まれている場合、LINQクエリから結合を削除することができ、コードの可読性が向上します。 – Steven

答えて

3

私はアナンドに同意する、あなたはLINQクエリが必要になります。これらはIQueryable<T> sおよびLINQであることを

SELECT * FROM RecordsTable rt WHERE rt.RecordID = TheRecordID AND EXISTS 
    (SELECT recordId FROM UserRecords ur WHERE ur.userId = TheUserID AND ur.recordID = rt.recordID) 

注:

var filterUserRecord = from u in MyDC.UserRecords 
         where u.UserID == TheUserID 
         select u; 

var q1 = from r in MyDC.RecordsTable 
      where r.RecordID = TheRecordID 
      where filterUserRecord.Any(f => f.RecordID == r.RecordID) 
      select r; 

これは、次のようなSQLクエリに変換されますクエリーを実行すると、もう1つのIQueryable<T>が生成されます。これには、クライアント側で単純に評価するのではなく、SQLに完全に変換される式(またはバックエンドが何であれ)が含まれます。

+0

私のクエリは動作していますか?私は最初にすべてのレコードを照会してからサブクエリーで1つだけを選択する必要はありません。遅すぎる。 – frenchie

+0

上記で貼り付けたクエリは、最初にRecordIDと同じRecordIDを持つレコードをクエリし、見つかったレコードに対してのみサブクエリを適用して、ユーザーが承認されていることを確認します。すべてのレコードが照会されるのは当てはまりません。 – Krizz

+0

あなたのクエリもうまく見えますが、私は私が少しだけ洗練されていると思っています。私はあなたのことがはるかに速いと確信しているわけではありませんが、可能性があります。私はいくつかのテストを行います。 – Krizz

3

さて、私はあなたの問題は、サブクエリ

SQLによって解決することができると思います:

select * from RecordsTable where recordId in 
(select recordId from UserRecords where userId = @someUserId) 
それはLINQの中でサブクエリのため

var filterUserRecord = from u in MyDC.UserRecords 
         where u.UserID == TheUserID 
         select u 

var q1 = from r in MyDC.RecordsTable 
     where filterUserRecord.Any(f => f.RecordID == r.RecordID) 

詳細を以下のようにLINQで表すことができる

- から読みますhere

+0

いいえ、すべてのUserRecordsを最初にロードする必要があります。遅すぎる。 – frenchie

+0

そうは思いません。「Any」はSQLの「EXISTS()」に変換されると思います。私の答えを見てください。 – Krizz

+0

LINQクエリは遅延評価されます。だから私は最初にfilterUserRecordが評価されるとは思っていません、そして、それは2番目のクエリに送られます。必要なデータを取得するには、どのようにしても両方のテーブルを一度トラバースする必要があります。 – Anand

1

お試しください:

var RecordToUpdate = (from u in MyDC.UserRecords 
         where u.UserTable.UserID == TheUserID 
         and u.RecordsTable.RecordID == TheRecord.RecordID).SingleOrDefault(); 

これは、UserIDとRecordIDを指定したクエリの結果を返します。

2

hereおそらく、SQLインジェクション(ここではセキュリティ上の主な懸念事項であると思われる)がLINQシナリオでどのように処理されるかについて説明しています。

EFのマイクロソフトのセキュリティ上の考慮事項については、hereという素晴らしい記事もあります。これらのツールを使って開発している人は、読んでみる価値があります!

[編集]あなたの最後のコメントに関して、このページに既に記載されているのと同様のクエリを使用できます。少しを凝縮するために:私はからのクエリを分離している

var targetRecords = 
    from userRecords in MyDC.UserRecords 
    where userRecords.UserTable.UserID == TheUserID 
    && userRecords.RecordsTable.RecordID == TheRecord.RecordID 
    select userRecords; 

var targetRecordsResult = targetRecords.SingleOrDefault(); 

:データベースがレコードIDが一意の主キーがあるという程度に、正規化されている場合は、バイパスが少し良く読み、クエリを作るために参加することができますtargetRecordsResultに代入するためにSingleOrDefaultを呼び出すまで、 'targetRecords'は評価されません。必要ならば、これを1つのステートメントにラップすることもできます。

上記のように、RecordIDが一意の主キーである場合は、一致するレコードを戻すか、またはnullを取得します。これが当てはまらない場合、つまりRecord以上のものが同じIDを持つ可能性がある場合、SingleOrDefault呼び出しは失敗することに注意してください。データベースがそのように設計されている場合は、Anandが指定したクエリに近いクエリを使用する必要があります。これはもう少し冗長ですが、その特定のユーザーのIDが一致するANYレコードが返されます。

セキュリティに関しては、SQL文がUserIDを含むコンパイルされ、改ざんを行うのが非常に難しいことに注意してください。したがって、この場合、UserIDの範囲と公開があなたの主な関心事であるという私の主張です。あなたが述べたように、ユーザー(および任意の潜在的な悪意のあるユーザー)が変数へのアクセス権を持たない場合(プロパティエクスポージャーなどを介して)、これはあなたのニーズに適した以上のものでなければなりません。

+0

私のクエリはそれのように機能しますか? – frenchie

+0

はい、ありますが、必要以上に冗長であることに注意してください。これは、TheUserId変数と同じくらい安全です。それが制御されて公開されていない場合、クエリがセキュリティ要件を満たしていない場合。他の人が指摘しているように、手動結合を必要とせず、定義された関係の使用に頼ることができます。これにより、クエリがわかりやすくなります。また、krizzのコメントにも注意してください。クエリはすべてのユーザーを取り戻すわけではなく、デフォルトではLINQクエリは作成された時点で実行されません。これは、生成されたSQLが効率的で安全であることを意味します。 – Nick

+0

よろしくお願いいたします。お使いのクエリのバージョンは?コード内。 UserIDフィールドはセッションに格納され、クライアントのページには送信されません。 – frenchie

関連する問題