[英]ASP.NET Identity 2 and Anonymous Users
在我们正在开发的电子商务解决方案中,我们使用的是AspNet Identity 2.2.1,要求任何来宾(匿名)用户必须先完成结帐,而无需事先注册该网站。 为了满足此要求,编写了一个名为UserMigrationAttribute的ActionFilter,该过滤器从cookie中获取SessionTrackId(字符串GUID)(如果未与请求cookie一起找到SessionTrackId,则从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;
}
}
任何帮助或建议都将受到高度赞赏。
谢谢,
发生这种情况是因为在cookie中设置了防伪令牌,该cookie直到下一个请求才会更新。 如果您是手动登录用户,则还应该发出重定向(即使重定向到他们已经前往的页面),只是为了确保cookie数据正确。 这通常是自然发生的,因为登录表单将在用户登录后重定向到需要授权的URL,从而消除了问题。 由于您当前未重定向,因此数据不同步。
但是,我不得不说,对于这个特定的用例,这似乎是一个非常糟糕的解决方案。 创建某种临时类型的用户并登录该用户以处理来宾签出,充其量只会在数据库中造成不必要的无用数据过剩,最坏的情况下会导致bug和类似的问题。
我还经营一个电子商务网站,我们处理客人结帐的方式非常简单。 结帐数据仅存储在会话中(电子邮件,送货/账单地址等)。 我们构建了一个视图模型来处理实际的结帐,提交销售所需的数据要么来自用户对象(如果已登录),要么来自这些会话变量(如果不是)。 如果用户既未登录,也未设置必需的会话变量,则它们将被重定向到收集帐单/运费等的入职表格。
对于其他方面,例如维护匿名购物车,我们使用带有购物车标识符的永久cookie。 如果该用户最终创建了一个帐户,我们将匿名购物车与其用户相关联,然后删除该cookie。 这样可以确保他们的购物车在会话超时和关闭浏览器之类的情况下都可以生存,即使他们是匿名的也是如此。
换句话说,在所有这些情况下,实际上不需要用户对象。 如果它在那里(用户已登录),很好,我们将使用它。 否则,我们将收集并保留通过其他方式结帐的必要信息。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.