ASP.NET Identity 2 и анонимные пользователи
В нашем развивающемся решении для электронной коммерции мы используем AspNet Identity 2.2.1, и требуется, чтобы все гостевые (анонимные) пользователи завершили оформление заказа без предварительной регистрации на сайте. Чтобы выполнить это требование, мы написали ActionFilter с именем UserMigrationAttribute, который получает SessionTrackId (строковый GUID) из cookie -файла, который мы устанавливаем из HttpModule для каждого запроса, если SessionTrackId не найден вместе с cookie -запросами, и создает и фактический IdentityUser в базе данных с имя пользователя что-то вроде SessionTrackId@mydomain.com.
Мы украсили наш класс BaseController этим атрибутом UserMigration, чтобы использовать его функции по всему сайту.
Все до этого момента работает, как и ожидалось, с одной единственной проблемой, которая возникает, когда страница загружается впервые для любого пользователя, если мы пытаемся выполнить Jquery Ajax-вызов метода, который имеет [ValidateAntiForgeryToken]
атрибут, вызов не удается сThe provided anti-forgery token was meant for a different claims-based user than the current user.
ошибка, даже если мы отправляем __RequestVerificationToken
параметр с каждым вызовом ajax.
Но если пользователь открывает другую страницу, щелкая ссылку и / или перезагружая / обновляя текущую страницу, все последующие вызовы 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;
}
}
Любая помощь или предложения высоко ценятся.
Спасибо,
1 ответ
Это происходит потому, что токен защиты от подделки установлен в файле cookie, который не будет обновляться до следующего запроса. Если вы регистрируете пользователя вручную, вы должны также выполнить перенаправление (даже если на ту же страницу, на которую он уже направлялся), просто чтобы убедиться, что данные cookie верны. Обычно это происходит естественным образом, поскольку форма входа перенаправляет на URL-адрес, для которого требуется авторизация, после входа пользователя, что устраняет проблему. Поскольку вы не перенаправляете в настоящее время, данные не синхронизированы.
Тем не менее, я должен сказать, что это кажется очень плохим решением для данного конкретного случая использования. Создание какого-либо временного пользователя и регистрация этого пользователя для обработки гостевой проверки создает в лучшем случае ненужный избыток бесполезных данных в вашей базе данных, а в худшем случае приводит к ошибкам и другим проблемам, таким как эта, с которой вы сталкиваетесь.
Я также управляю сайтом электронной коммерции, и то, как мы справляемся с проверкой гостей, невероятно упрощено. Данные оформления заказа просто сохраняются в сеансе (электронная почта, адрес доставки / выставления счета и т. Д.). Мы строим модель представления для обработки фактического оформления заказа, когда данные, необходимые для отправки продажи, поступают либо от объекта пользователя, если они вошли в систему, либо от этих переменных сеанса, если они этого не делают. Если пользователь не вошел в систему и не установил необходимые переменные сеанса, то они перенаправляются в форму регистрации, где собираются биллинг / доставка и т. Д.
Для других аспектов, таких как сохранение анонимной корзины, мы используем постоянный файл cookie с идентификатором корзины. Если пользователь завершает создание учетной записи, мы связываем анонимную корзину с его пользователем, а затем удаляем cookie. Это гарантирует, что их корзина сохранится после истечения времени ожидания сеанса и таких вещей, как закрытие браузера, даже если они анонимны.
Другими словами, во всех этих вещах пользовательский объект фактически не нужен. Если он есть (пользователь вошел в систему), отлично, мы будем его использовать. В противном случае мы собираем и сохраняем необходимую информацию для оформления заказа другими способами.