【问题标题】:ASP.NET Identity 2 and Anonymous UsersASP.NET Identity 2 和匿名用户
【发布时间】:2018-01-11 06:29:58
【问题描述】:

在我们开发的电子商务解决方案中,我们使用的是 AspNet Identity 2.2.1,并且要求任何来宾(匿名)用户都必须在未事先注册网站的情况下完成结帐。为了满足这个要求,我们编写了一个名为 UserMigrationAttribute 的 ActionFilter,它从 cookie 中获取 SessionTrackId(字符串 GUID)——如果没有找到 SessionTrackId 和请求 cookie,我们从 HttpModule 为每个请求设置它——并在数据库中创建和实际 IdentityUser用户名类似于 SessionTrackId@mydomain.com。

我们用这个 UserMigration 属性修饰了我们的 BaseController 类,以便在整个站点中利用它的功能。

到目前为止,一切都按预期工作,只有一个缺点问题,即当任何用户第一次加载页面时,如果我们尝试对具有 [ValidateAntiForgeryToken] 属性的方法进行 Jquery Ajax 调用,调用失败并出现“The provided anti-forgery token was meant for a different claims-based user than the current user.”错误,即使我们在每个 ajax 调用中都发送了__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;

        }

    }

非常感谢任何帮助或建议。

谢谢,

【问题讨论】:

    标签: c# asp.net-mvc asp.net-identity anonymous-users


    【解决方案1】:

    发生这种情况是因为防伪令牌设置在 cookie 中,直到下一个请求才会更新。如果您手动登录用户,您还应该发出重定向(即使他们已经前往同一页面),只是为了确保 cookie 数据正确。这通常会自然发生,因为登录表单会在用户登录后重定向到需要授权的 URL,从而消除问题。由于您当前没有重定向,因此数据不同步。

    但是,我不得不说,对于这个特定的用例来说,这似乎是一个非常糟糕的解决方案。创建某种临时类型的用户并让该用户登录以处理客人结帐会在您的数据库中创建不必要的过多无用数据,充其量会导致错误和其他类似您遇到的问题,最坏的情况。

    我还经营一个电子商务网站,我们处理客人结帐的方式非常简单。结帐数据仅存储在会话中(电子邮件、送货/账单地址等)。我们构建了一个视图模型来处理实际的结帐,其中提交销售所需的数据来自用户对象(如果他们已登录)或这些会话变量(如果未登录)。如果用户既没有登录,也没有设置必要的会话变​​量,那么他们将被重定向到收集帐单/运输等的入职表单。

    对于维护匿名购物车等其他方面,我们使用带有购物车标识符的永久 cookie。如果用户最终创建了一个帐户,我们会将匿名购物车与他们的用户相关联,然后删除 cookie。这样可以确保他们的购物车在会话超时和关闭浏览器之类的事情之后仍然存在,即使他们是匿名的。

    换句话说,在所有这些事情中,实际上都不需要用户对象。如果它在那里(用户已登录),很好,我们将使用它。否则,我们会通过其他方式收集并保存结帐所需的信息。

    【讨论】:

    • 感谢您的回复和指导,这是公认的答案,因为它建议(自我)在 filterContext 上重定向,从而解决了我们的问题。
    猜你喜欢
    • 2014-06-05
    • 1970-01-01
    • 2014-06-06
    • 1970-01-01
    • 2017-07-07
    • 1970-01-01
    • 2015-04-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多