2

開発中の e コマース ソリューションでは、AspNet Identity 2.2.1 を使用しており、ゲスト (匿名) ユーザーは Web サイトに事前登録せずにチェックアウトを完了する必要があります。この要件を満たすために、Cookie から SessionTrackId (文字列 GUID) を取得する UserMigrationAttribute という名前の ActionFilter を作成しました。ユーザー名は、SessionTrackId@mydomain.com のようなものです。

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

この時点までのすべては、単一の欠点の問題で期待どおりに機能します。これは、任意のユーザーに対してページが初めて読み込まれるときです。[ValidateAntiForgeryToken]属性を持つメソッドへの Jquery Ajax 呼び出しを実行しようとすると、呼び出しは失敗します。すべての ajax 呼び出しでパラメーターをThe provided anti-forgery token was meant for a different claims-based user than the current user.送信しているにもかかわらず、' ' エラー。__RequestVerificationToken

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

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

以下の 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;

        }

    }

ヘルプや提案は大歓迎です。

ありがとうございました、

4

1 に答える 1

4

これは、偽造防止トークンが Cookie に設定されており、次のリクエストまで更新されないために発生しています。ユーザーを手動でサインインしている場合は、Cookie データが正しいことを確認するためだけに、リダイレクトも発行する必要があります (ユーザーが既にアクセスしていたページと同じページであっても)。これは通常、ユーザーがサインインした後に認証が必要な URL にサインイン フォームがリダイレクトされるため、自然に発生し、問題が解消されます。現在リダイレクトしていないため、データが同期していません。

ただし、これは、この特定のユース ケースに対する非常に貧弱なソリューションのように思われると言わざるを得ません。ある種の一時的なタイプのユーザーを作成し、ゲスト チェックアウトを処理するためにそのユーザーをサインインさせると、せいぜいデータベースに無用なデータの不必要な過剰が作成され、最悪の場合、このようなバグやその他の問題が発生する可能性があります。

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

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

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

于 2017-08-03T17:19:51.417 に答える