2017-08-03 18 views
1

開発中の電子商取引ソリューションではAspNet Identity 2.2.1を使用しており、ゲスト(匿名)ユーザーは事前にWebサイトに登録しなくてもチェックアウトを完了する必要があります。この要件を満たすために、UserTrackId(文字列GUID)を取得するUserMigrationAttributeという名前のActionFilterが記述されています.SessionTrackId(文字列GUID)はリクエストCookieと共にSessionTrackIdが見つからない場合はすべてのリクエストに対してHttpModuleから設定し、 usernameは[email protected]のようなものです。ASP.NET ID 2と匿名ユーザー

このUserMigration属性でBaseControllerクラスを装飾して、サイト全体でその機能を利用しました。

これまでのすべてのことは、いずれのユーザーに対してもページが初めてロードされている場合、[ValidateAntiForgeryToken]属性を持つメソッドへのJquery Ajax呼び出しを作成しようとすると、すべてのajax呼び出しで__RequestVerificationTokenパラメータを送信していても、呼び出しは 'The provided anti-forgery token was meant for a different claims-based user than the current user.'というエラーで失敗します。

しかし、ユーザーがリンクをクリックして別のページを開いたり、現在のページを再読み込み/更新したりすると、その後のすべてのajax呼び出しが正常に完了します。

私たちの理解では、UserMigrationAttributeはOnActionExecutingメソッドでユーザーを作成しますが、@ Html.AntiForgeryToken()が適切な値で更新されていないプロセスでsignInした後にユーザーを作成します。

以下のUserMigrationAttributeコードがあります。

[AttributeUsage(AttributeTargets.Class)] 
    public class UserMigrationAttribute : ActionFilterAttribute 
    { 
     public ApplicationSignInManager SignInManager(ActionExecutingContext filterContext) 
     { 
      return filterContext.HttpContext.GetOwinContext().Get<ApplicationSignInManager>(); 
     } 

     public UserManager UserManager(ActionExecutingContext filterContext) 
     { 
      return filterContext.HttpContext.GetOwinContext().GetUserManager<UserManager>(); 
     } 

     public override void OnActionExecuting(ActionExecutingContext filterContext) 
     { 
      CreateMigrateCurrentUser(filterContext); 
      base.OnActionExecuting(filterContext); 
     } 

     private static readonly object LockThis = new object(); 

     private void CreateMigrateCurrentUser(ActionExecutingContext filterContext) 
     { 
      lock (LockThis) 
      { 
       var signInManager = SignInManager(filterContext); 
       var userManager = UserManager(filterContext); 

       var sessionTrackId = GetSessionTrackId(filterContext); 

       if (!filterContext.HttpContext.Request.IsAuthenticated) 
       { 
        if (!string.IsNullOrEmpty(sessionTrackId)) 
        { 
         var username = string.Format("{0}@mydomain.com", sessionTrackId); 
         var user = userManager.FindByName(username); 

         if (user == null) 
         { 
          user = new User() {UserName = username, Email = username}; 
          var result = userManager.Create(user); 
          userManager.AddToRole(user.Id, StringResources.AnonymousVisitorsGroup); 
         } 

         signInManager.SignIn(user, true, true); 
        } 
       } 
       else 
       { 
        if (!string.IsNullOrEmpty(sessionTrackId)) 
        { 
         var username = string.Format("{0}@mydomain.com", sessionTrackId); 
         var user = userManager.FindByName(username); 

         if (user != null) 
         { 
          if (!HttpContext.Current.User.IsInRole(StringResources.AnonymousVisitorsGroup)) 
          { 
           var targetUserId = HttpContext.Current.User.Identity.GetUserId<int>(); 

           var service = new Service(); 
           service.Users.MigrateUser(user.Id, targetUserId); 
          } 
         } 
        } 
       } 

      } 

     } 

     private string GetSessionTrackId(ActionExecutingContext filterContext) 
     { 
      var retVal = string.Empty; 
      if (filterContext.HttpContext.Request.Cookies["stid"] != null) 
      { 
       retVal = filterContext.HttpContext.Request.Cookies["stid"].Value; 
      } 

      return retVal; 

     } 

    } 

ご意見やご提案は高く評価されます。

は偽造防止トークンが次のリクエストまで更新されませんクッキー、に設定されているので、これが起こっている

答えて

1

、ありがとうございます。あなたが手動でサインインしている場合は、クッキーデータが正しいことを確認するために、リダイレクトを発行する必要があります(すでに同じページにいる場合でも)。サインインフォームは、ユーザーがサインインした後に承認が必要なURLにリダイレクトされるため、通常は自然に発生します。したがって、問題は否定されます。現在リダイレクトしていないため、データは同期していません。

しかし、私はこれがこの特定のユースケースに対して非常に貧弱な解決策であると言わなければならないと言わなければなりません。何らかの一時的なタイプのユーザーを作成し、そのユーザーがゲストのチェックアウトを処理するために署名することで、データベース内の無駄なデータが無駄になり、最悪の場合、このようなバグやその他の問題が発生します。

私は電子商取引サイトも運営しています。ゲストのチェックアウトの処理方法は非常に単純です。チェックアウトデータは、セッション(電子メール、配送先/請求先住所など)に保存されます。実際のチェックアウトを処理するためのビューモデルを構築します。ここで、セールに必要なデータは、ユーザーオブジェクト(ログインしている場合)またはセッション変数(存在しない場合)のいずれかになります。ユーザーがログインしておらず、必要なセッション変数が設定されていない場合、課金/出荷などの収集された入荷フォームにリダイレクトされます。

匿名カートを維持するなどのその他の面では、カート識別子を持つ永続的なクッキーを使用します。ユーザーがアカウントの作成を終了すると、匿名カートをそのユーザーに関連付けてから、Cookieを削除します。これにより、たとえ匿名の場合であっても、カートがセッションのタイムアウトやブラウザの終了などを過ぎても存続することが保証されます。

つまり、これらのすべてでは、実際にユーザーオブジェクトは必要ありません。そこにいる(ユーザーがログインしている)場合は、それを使用します。それ以外の場合は、他の方法でチェックアウトのために必要な情報を収集し、保持します。

+0

ご回答いただきありがとうございます。これはfilterContextにリダイレクトされ、私たちの問題を解決することを示唆しています。 –

関連する問題