1

私は、非常に一般的なタスクであると私が信じていることをどの方向に進めるかについて、ちょっとしたつまずきにぶつかりました。ログインしたユーザーがデータの編集を許可されていることをどこで確認しますか。この場合、aUserには Id、EmailAddress、Name、およびAddressオブジェクトのコレクションがあります。にAddressはいくつかのプロパティが含まれており、そのうちの 1 つは UserId であり、所属するユーザーの ID です。Addressユーザーは、自分に属するオブジェクトの編集のみを許可する必要があります。いつ/どこで編集するAddressときは、ユーザーが編集を許可されていることを確認します。

今週、ASP.NET MVC3 を学習したばかりで、それを実践しています。デフォルトの MembershipProvider を使用してユーザーをログインさせる Web アプリケーションを作成しました (後日、これをカスタムのものに置き換えます)。最終的な結果として、ログイン後User.Identity.Name、コントローラーのプロパティはユーザーの電子メール アドレスを返します。

ユーザーが自分の詳細を表示したい場合は、 でAddressesアクションを呼び出しますAccountController。以下のように。

[Authorize]
public ActionResult Addresses()
{
    IEnumerable<Address> addresses = _myService.GetUserAddresss(User.Identity.Name));
    return View(addresses);
}

ユーザーが住所の詳細を編集したい場合、住所を取得して表示するアクションと、編集内容を住所に保存するアクションを呼び出すことができます。

[Authorize]
public ActionResult Address(int id)
{
    Address address= _myService.GetAddress(id));
    return View(address);
}

[Authorize]
[HttpPost]
public ActionResult Address(EditAddressModel model)
{
    Address address = _myService.SaveDetail(model.Address));
    return View(address );
}

上記の方法の欠点は、ユーザーが url にアクセスした場合../Account/Address/12です。Addressその後、作成したかどうかに関係なく、ID 12の を表示および編集できます(存在する場合)。

私はN層のアプローチに従っています。そのため、コントローラーがサービスと通信し、サービスがビジネス ロジック レイヤーと通信し、リポジトリと通信し、最後に Entity Framework 4 を使用してデータベースと通信します。承認チェックはどこで行う必要がありますか?

次の解決策を検討しましたが、適切なアプローチを決定できません。

アイデア1

コントローラー クラスでは、コントローラーが User.Identity.Name プロパティにアクセスできるため。このプロパティを使用して、サービスから返されたアドレスのユーザー ID が現在ログインしているユーザーと一致するかどうかを確認できます。そうでない場合は、エラー ページを表示します。それ以外の場合は、通常どおり表示/編集します。

Address利点 - シンプルな実装。サービスがオブジェクトを返した後に if ステートメントを追加するだけです。コントローラーは User.Identity.Name にアクセスできます。

欠点 - データはコントローラーに返されます。コントローラーは、ユーザーがそれを見ることができないと判断します。「ユーザーだけが自分のアドレスを編集できる」というビジネスロジックがコントローラーに忍び込んでいるような気がします。

アイデア2

ビジネス層。コントローラーは、userId と detailId ( _myService.GetAddress(User.Identity.Name, detailId));) を使用してサービスを呼び出します。これにより、ビジネス レイヤーが呼び出されます。ビジネス層にはメソッドpublic Address GetAddress(int userId, int addressId)があります ビジネス層は、データベースから を取得するように要求されるとAddress、返されたアドレスがユーザーのものであることを確認して返します。そうでない場合は null を返します。したがって、コントローラーはサービスから null 応答を取得し、適切なエラー メッセージを表示します。

利点 - ユーザーが詳細を編集するだけのビジネス ロジックは、ビジネス レイヤーにあります。

短所 - ビジネス ロジックは User.Identity.Name にアクセスできないため、サービス クラスとビジネス クラスの各メソッドには userId パラメータが必要になります。

アイデア3

上記と同様に、Service および Business レイヤー クラスには UserId というプロパティがあります。これは、ユーザーがデータベース リソースにアクセスできるかどうかを確認するために使用されます。これは、作成中またはサービスを呼び出す前に設定できます。すなわち

[Authorize]
public ActionResult Address(int id)
{
    _myService.User = User.Identity.Name;
    Address address = _myService.GetAddress(id));
    return View(address);
}

利点 - ユーザーが詳細を編集するだけのビジネス ロジックは、ビジネス レイヤーにあります。各メソッド呼び出しに userId を渡す必要はありません。

欠点 - このアプローチを使用する例を見たことがありません。そして、私はそれが正しいとは思いません。サービス層として WCF を使用しているわけではありません。しかし、もしそうなら、この余分なプロパティを持つことはうまくいかないでしょう。

アイデア4

ビジネス層の User.Identity.Name にアクセスします。コントローラーからサービスを介してビジネス層に渡す必要はありません。それが可能かどうかはわかりません。

4

2 に答える 2

1

すべてのクエリにユーザーの ID を含めるだけです。アイデア 2 でこれを行いました。セキュリティ監査の一環として、チームの一部としてこれを行う場合、すべてのデータ アクセス メソッドにパラメーターが含まれていることを確認し、そのユーザー ID または名前を DB へのクエリで where 句で使用していることを確認します。統合テストは、ユーザーの 1 つのレコードを作成し、別のユーザー名パラメーターを渡すメソッドを呼び出して、id でそれをロードしようとするのに役立ちます。

于 2012-06-24T16:48:53.550 に答える
1

ビジネスロジックレイヤーで承認を行うことをお勧めします。現在のユーザーのプリンシパルには、アプリケーション内のどこからでもアクセスできます (同じアプリ ドメインである限り)。静的メンバー HttpContext.Current にアクセスするだけで、現在の HttpContext のユーザー プリンシパルを取得できます。

プリンシパル HttpContext.Current.User

明らかに、このコードを含むアセンブリは System.Web を参照する必要があります。それは Web アプリでは大きな問題になるべきではないと思います。

この静的メンバーへの呼び出しからビジネス ロジックをさらに切り離すには、Adapter パターンを使用して呼び出しをラップし、ユーザーの原則を取得することをお勧めします。このようにして、他の認証/承認フレームワークを優先してメンバーシップを捨てることにした場合、またはそれをモックアウトすることを選択した場合、HttpContext.Current への具体的な結合はありません。

以下は、現在のコンテキストのユーザー プリンシパルにアクセスするアダプターの例です。

public interface IUserAdapter
{
    IPrincipal GetUserPrincipal();
    void SetAuthenticationCookie(IUser user);
    void SignOut();
}

// my business logic representation of a user
public interface IUser
{
    int Id { get; set; }
    string Name { get; set; }
}

public class WebUserAdapter : IUserAdapter
{
    public IPrincipal GetUserPrincipal()
    {
        return HttpContext.Current.User;
    }

    public void SetAuthenticationCookie(IUser user)
    {
        FormsAuthentication.SetAuthCookie(user.Id.ToString(), false);
    }

    public void SignOut()
    {
        FormsAuthentication.SignOut();
    }
}
于 2012-06-24T16:50:00.263 に答える