Токен защиты от подделки предназначен для пользователя ""но текущий пользователь-это" имя пользователя"
Я создаю одностраничное приложение и испытываю проблему с маркерами защиты от подделки.
Я знаю, почему проблема происходит, я просто не знаю, как это исправить.
я получаю ошибку, когда происходит следующее:
- незарегистрированный пользователь загружает диалоговое окно (с сгенерированным токеном защиты от подделки)
- пользователь закрывает диалоговое окно
- пользователь входит в систему
- пользователь открывает тот же диалог
- пользователь отправляет форму в диалоге
маркер защиты от подделки предназначен для пользователя "" но текущий пользователь "имя пользователя"
причина этого заключается в том, что мое приложение на 100% одностраничное, и когда пользователь успешно входит в систему через ajax post в /Account/JsonLogin
, Я просто переключаю текущие представления с" аутентифицированными представлениями", возвращенными с сервера, но не перезагружайте страницу.
Я знаю, что это причина, потому что если я простая перезагрузка страницы между шагами 3 и 4, нет ошибки.
получается, что @Html.AntiForgeryToken()
в загруженной форме по-прежнему возвращает маркер для старого пользователя, пока страница не будет перезагружена.
как я могу изменить @Html.AntiForgeryToken()
чтобы вернуть токен для нового аутентифицированного пользователя?
Я ввожу новый GenericalPrincipal
с пользовательским IIdentity
на каждые Application_AuthenticateRequest
так @Html.AntiForgeryToken()
вызывается HttpContext.Current.User.Identity
это, на самом деле моя пользовательская идентичность с IsAuthenticated
набор свойств к истине и все же @Html.AntiForgeryToken
по-прежнему кажется, чтобы сделать токен для старого пользователя, если я не делаю перезагрузку страницы.
10 ответов:
это происходит потому, что анти-подделки маркер используется имя пользователя в качестве части зашифрованного маркера для лучшей проверки. При первом вызове
@Html.AntiForgeryToken()
пользователь не вошел в систему, поэтому маркер будет иметь пустую строку для имени пользователя, после входа пользователя в систему, если вы не замените маркер защиты от подделки, он не пройдет проверку, потому что первоначальный маркер был для анонимного пользователя, и теперь у нас есть аутентифицированный пользователь с известным именем пользователя.у вас есть несколько вариантов решения этой проблемы:
только на этот раз пусть ваш спа-центр сделает полный пост, и когда страница перезагрузится, у нее будет маркер защиты от подделки с внедренным обновленным именем пользователя.
есть частичный вид только с
@Html.AntiForgeryToken()
и сразу после входа в систему выполните еще один запрос AJAX и замените существующий маркер защиты от подделки ответом на запрос.просто отключите проверку личности анти-подделка выполняется проверка. Добавьте следующее к вашему событий Application_Start способ:
AntiForgeryConfig.SuppressIdentityHeuristicChecks = true
.
чтобы исправить ошибку вам нужно разместить
OutputCache
Аннотация данных на GetActionResult
страницы входа в систему как:[OutputCache(NoStore=true, Duration = 0, VaryByParam= "None")] public ActionResult Login(string returnUrl)
Это происходит много раз с моим приложением, поэтому я решил google для него!
Я нашел простое объяснение этой ошибки! Пользователь дважды щелкает кнопку для входа в систему! Вы можете увидеть другого пользователя, говорящего об этом по ссылке ниже:
Я надеюсь, что это помогает! =)
У меня была та же проблема, и этот грязный хак исправил ее, по крайней мере, пока я не смогу исправить ее более чистым способом.
public ActionResult Login(string returnUrl) { if (AuthenticationManager.User.Identity.IsAuthenticated) { AuthenticationManager.SignOut(); return RedirectToAction("Login"); }
...
У меня была довольно специфическая, но похожая проблема в процессе регистрации. Как только пользователь нажал на ссылку электронной почты, отправленную им, они вошли в систему и отправили прямо на экран сведений об учетной записи, чтобы заполнить дополнительную информацию. Мой код:
Dim result = Await UserManager.ConfirmEmailAsync(userId, code) If result.Succeeded Then Dim appUser = Await UserManager.FindByIdAsync(userId) If appUser IsNot Nothing Then Dim signInStatus = Await SignInManager.PasswordSignInAsync(appUser.Email, password, True, shouldLockout:=False) If signInStatus = SignInStatus.Success Then Dim identity = Await UserManager.CreateIdentityAsync(appUser, DefaultAuthenticationTypes.ApplicationCookie) AuthenticationManager.SignIn(New AuthenticationProperties With {.IsPersistent = True}, identity) Return View("AccountDetails") End If End If End If
Я обнаружил, что представление возврата ("AccountDetails") давало мне исключение токена, я предполагаю, потому что функция ConfirmEmail была украшена AllowAnonymous, но функция AccountDetails имела ValidateAntiForgeryToken.
изменение возврата на Return RedirectToAction ("AccountDetails") решило проблему для меня.
У меня есть то же самое исключение, происходящее большую часть времени на рабочем сервере.
Почему это происходит?
это происходит, когда пользователь войти с действительными учетными данными и после входа в систему и перенаправить на другую страницу, и после того, как они нажимают кнопку Назад покажет страницу входа и снова он ввел действительные учетные данные, что время это исключение будет происходить.
как решить?
просто добавьте эту строку и работать идеально, нет получить ошибку.
[OutputCache(NoStore = true, Duration = 0, VaryByParam = "None")]
[OutputCache(NoStore=true, Duration=0, VaryByParam="None")] public ActionResult Login(string returnUrl)
вы можете проверить это, поставив точку останова в первой строке вашего действия входа (Get). Перед добавлением директивы OutputCache точка останова будет хит на первой загрузке, но после нажатия на кнопку Назад в браузере не. После добавления директивы вы должны в конечном итоге с точки останова попадания каждый раз, поэтому AntiForgeryToken будет правильно, а не пустой.
у меня была такая же проблема с одной страницей ASP.NET MVC Core application. Я решил это, установив
HttpContext.User
во всех действиях контроллера, которые изменяют текущие утверждения идентификации (поскольку MVC делает это только для последующих запросов, как обсуждалось здесь). Я использовал фильтр результатов вместо промежуточного программного обеспечения, чтобы добавить файлы cookie antiforgery к моим ответам, которые убедились, что они были созданы только после того, как действие MVC вернулось.контроллер (NB. Я управляю пользователями с помощью ASP.NET ядро идентичности):
[Authorize] [ValidateAntiForgeryToken] public class AccountController : Controller { private SignInManager<IdentityUser> signInManager; private UserManager<IdentityUser> userManager; private IUserClaimsPrincipalFactory<IdentityUser> userClaimsPrincipalFactory; public AccountController(SignInManager<IdentityUser> signInManager, UserManager<IdentityUser> userManager, IUserClaimsPrincipalFactory<ApplicationUser> userClaimsPrincipalFactory) { this.signInManager = signInManager; this.userManager = userManager; this.userClaimsPrincipalFactory = userClaimsPrincipalFactory; } [HttpPost] [AllowAnonymous] public async Task<IActionResult> Login(string username, string password) { if (username == null || password == null) { return BadRequest(); // Alias of 400 response } var result = await signInManager.PasswordSignInAsync(username, password, false, lockoutOnFailure: false); if (result.Succeeded) { var user = await userManager.FindByNameAsync(username); // Must manually set the HttpContext user claims to those of the logged // in user. Otherwise MVC will still include a XSRF token for the "null" // user and token validation will fail. (MVC appends the correct token for // all subsequent reponses but this isn't good enough for a single page // app.) var principal = await userClaimsPrincipalFactory.CreateAsync(user); HttpContext.User = principal; return Json(new { username = user.UserName }); } else { return Unauthorized(); } } [HttpPost] public async Task<IActionResult> Logout() { await signInManager.SignOutAsync(); // Removing identity claims manually from the HttpContext (same reason // as why we add them manually in the "login" action). HttpContext.User = null; return Json(new { result = "success" }); } }
фильтр результатов для добавления файлов cookie antiforgery:
public class XSRFCookieFilter : IResultFilter { IAntiforgery antiforgery; public XSRFCookieFilter(IAntiforgery antiforgery) { this.antiforgery = antiforgery; } public void OnResultExecuting(ResultExecutingContext context) { var HttpContext = context.HttpContext; AntiforgeryTokenSet tokenSet = antiforgery.GetAndStoreTokens(context.HttpContext); HttpContext.Response.Cookies.Append( "MyXSRFFieldTokenCookieName", tokenSet.RequestToken, new CookieOptions() { // Cookie needs to be accessible to Javascript so we // can append it to request headers in the browser HttpOnly = false } ); } public void OnResultExecuted(ResultExecutedContext context) { } }
Автозагрузка.КС выдержка:
public partial class Startup { public Startup(IHostingEnvironment env) { //... } public IConfigurationRoot Configuration { get; } public void ConfigureServices(IServiceCollection services) { //... services.AddAntiforgery(options => { options.HeaderName = "MyXSRFFieldTokenHeaderName"; }); services.AddMvc(options => { options.Filters.Add(typeof(XSRFCookieFilter)); }); services.AddScoped<XSRFCookieFilter>(); //... } public void Configure( IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { //... } }
сообщение появляется при входе в систему, когда вы уже прошли проверку подлинности.
этот помощник делает то же самое, что и .
System.Web.Helpers.AntiForgery.Validate()
удалить
[ValidateAntiForgeryToken]
attribut от контроллера и поместите этот помощник в действие methode.поэтому, когда пользователь уже аутентифицирован, перенаправьте на домашнюю страницу или, если не продолжите проверку действительного маркера защиты от подделки после этой проверки.
if (User.Identity.IsAuthenticated) { return RedirectToAction("Index", "Home"); } System.Web.Helpers.AntiForgery.Validate();
To попытайтесь воспроизвести ошибку, выполните следующие действия: Если вы находитесь на своей странице входа, и вы не прошли проверку подлинности. Если вы дублируете вкладку и входите во вторую вкладку. И если вы вернетесь на первую вкладку на странице входа в систему, и вы пытаетесь войти в систему без перезагрузки страницы ... у вас есть эта ошибка.
есть проблема с проверкой анти-подделки токенов в интернет-магазине: пользователи открывают много вкладок (с товарами) и после входа в один пытаются войти в другой и получили такое исключение AntiForgeryException. Итак, AntiForgeryConfig.SuppressIdentityHeuristicChecks = true не помогло мне, поэтому я использовал такой уродливый hackfix, может быть, это будет полезно для кого-то:
public class ExceptionPublisherExceptionFilter : IExceptionFilter { public void OnException(ExceptionContext exceptionContext) { var exception = exceptionContext.Exception; var request = HttpContext.Current.Request; if (request != null) { if (exception is HttpAntiForgeryException && exception.Message.ToLower().StartsWith("the provided anti-forgery token was meant for user \"\", but the current user is")) { var isAjaxCall = string.Equals("XMLHttpRequest", request.Headers["x-requested-with"], StringComparison.OrdinalIgnoreCase); var returnUrl = !string.IsNullOrWhiteSpace(request["returnUrl"]) ? request["returnUrl"] : "/"; var response = HttpContext.Current.Response; if (isAjaxCall) { response.Clear(); response.StatusCode = 200; response.ContentType = "application/json; charset=utf-8"; response.Write(JsonConvert.SerializeObject(new { success = 1, returnUrl = returnUrl })); response.End(); } else { response.StatusCode = 200; response.Redirect(returnUrl); } } } ExceptionHandler.HandleException(exception); } } public class FilterConfig { public static void RegisterGlobalFilters(GlobalFilterCollection filters) { filters.Add(new ExceptionPublisherExceptionFilter()); filters.Add(new HandleErrorAttribute()); } }
думаю, это будет здорово, если анти-подделка-параметры генерации токенов могут быть установлены, чтобы исключить имя пользователя или что-то вроде что.