8

次の ntier アプリがあります: MVC > サービス > リポジトリ > ドメイン。フォーム認証を使用しています。現在ログインしているアプリケーションのユーザーを取得するために MVC レイヤーの外部で Thread.CurrentPrincipal を使用しても安全ですか? それとも HttpContext.Current.User を使用する必要がありますか?

私が尋ねる理由は、Thread.CurrentPrincipal の周りにいくつかの問題があるようですが、将来的に非 Web フォント エンドを提供する必要がある場合に備えて、MVC レイヤーの外側に System.Web への参照を追加するように注意しています。

アップデート

これまでに受け取ったアドバイスに従って、呼び出されるメソッドのパラメーターの一部としてユーザー名をサービスに渡しました。これにより、元の質問が改善されました。多くの Service および Domain メソッドで、ユーザーが特定のロールに属しているかどうかを確認できる必要があります。これにはいくつかの解決策があるようですが、どれが最善の方法なのか疑問に思っています。

  1. ユーザー名だけでなく、HttpContext.Current.User 全体をパラメーターとして渡します。
  2. Web 層の外で Thread.CurrentPrincipal を呼び出し、それを使用します。しかし、それが HttpContext.Current.User と等しいことを確認するにはどうすればよいでしょうか?
  3. これまでに提案されたようにユーザー名を渡すことに固執し、Roles.IsUserInRole を使用します。このアプローチの問題は、System.Web への参照が必要であり、MVC レイヤーの外では正しくないと感じていることです。

どのように進めることをお勧めしますか?

4

5 に答える 5

2

私もしませんが、HttpContext.Current.UserあなたのWebレイヤーに固有です。

ユーザー名をサービスレイヤーに挿入してみませんか?

于 2012-07-18T14:39:36.463 に答える
2

Thread.CurrentPrincipalまたはに依存しないように、ユーザー情報を抽象化する必要がありますHttpContext.Current.User

たとえば、ユーザー名を受け入れるコンストラクターまたはメソッドパラメーターを追加できます。

コンストラクターパラメーターの非常に単純化された例を次に示します。

class YourBusinessClass 
{
   string _userName;
   public YourBusinessClass(string userName)
   {
      _userName = userName;
   }

   public void SomeBusinessMethodThatNeedsUserName()
   {
      if (_userName == "sally")
      {
         // do something for sally
      }
   }
}
于 2012-07-18T14:39:58.403 に答える
2

私はオプション番号 2 を好みます (Web 層の外で Thread.CurrentPrincipal を使用します)。これは、サービス層とデータ層のメソッドを汚染しないためです。ボーナス付き: 役割と追加情報をカスタム プリンシパルに保存できます。

サービス層とデータ層の Thread.CurrentPrincipal が Web 層と同じであることを確認します。Global.asax(Application_AuthenticateRequest) で HttpContext.Current.User (Context.User) を設定できます。これを設定できる他の代替場所が下部に追加されます。

サンプルコード:

    //sample synchronizing HttpContext.Current.User with Thread.CurrentPrincipal
    protected void Application_AuthenticateRequest(Object sender, EventArgs e)
    {
        HttpCookie authCookie = Request.Cookies[FormsAuthentication.FormsCookieName];

        //make sure principal is not set for anonymous user/unauthenticated request
        if (authCookie != null && Request.IsAuthenticated)
        {
            FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value);

            //your additional info stored in cookies: multiple roles, privileges, etc
            string userData = authTicket.UserData;

            CustomPrincipal userPrincipal = PrincipalHelper.CreatePrincipal(authTicket.Name, authTicket.UserData, Request.IsAuthenticated);

            Context.User = userPrincipal;
        }
    }

もちろん、最初にログイン フォームを実装して、カスタム プリンシパルを含む認証 Cookie を作成する必要があります。

Application_AuthenticateRequest は、サーバーへのすべてのリクエスト (css ファイル、javascript ファイル、画像ファイルなど) に対して実行されます。この機能をコントローラー アクションのみに制限するには、ActionFilter でカスタム プリンシパルを設定してみてください (私はこれを試していません)。私が試したのは、この機能をコントローラーのインターセプター内に設定することです(依存性注入とアスペクト指向プログラミングにCastle Windsorを使用しています)。

于 2012-08-29T04:55:34.463 に答える
2

関連するユーザーの詳細を new にマップしClassて LoggedInUser を表し、それを引数としてビジネス レイヤー メソッドに渡します。

 public class LoggedInUser
 {
   public string UserName { set;get;}
   //other relevant proerties
 }

この値を設定し、BL メソッドに渡します

var usr=new LoggedInUser();
usr.UserName="test value ";  //Read from the FormsAuthentication stuff and Set
var result=YourBusinessLayerClass.SomeOperation(usr);
于 2012-07-18T14:41:42.973 に答える
1

ドメインの責任をさらに制限する必要があるため、この問題が発生していると思います。承認を処理するのは、サービスまたはドキュメントの責任ではありません。現在のユーザーはドメインではなくWebアプリにログインしているため、その責任はMVCレイヤーで処理する必要があります。

サービスまたはドキュメントから現在のユーザーを検索する代わりに、MVCアプリでチェックを実行すると、次のようになります。

if(Roles.IsUserInRole("DocumentEditorRole")){

    //UpdateDocument does NOT authorize the user. It does only 1 thing, update the document.
    myDocumentService.UpdateDocument(currentUsername, documentToEdit);

} else {

    lblPermissionDenied.InnerText = @"You do not have permission 
                                      to edit this document.";

}

これはクリーンで読みやすく、サービスとドメインクラスを承認の懸念から解放することができます。ビューモデルにマップRoles.IsUserInRole("DocumentEditorRole")することはできますが、失うのはDocumentクラスのCurrentUserCanEditメソッドだけです。しかし、ドメインモデルを実世界のオブジェクトを表すものと考える場合、そのメソッドはとにかくDocumentに属していません。ドメインユーザーオブジェクト()のメソッドと考えるかもしれませんがuser.CanEditDocument(doc)、全体として、ドメインレイヤーから認証を除外すると、より幸せになると思います。

于 2013-01-07T06:07:09.593 に答える