MVC5 AntiForgeryToken Claims/Sequence содержит более одного элемента

Случай: у меня есть приложение MVC5 (в основном шаблон MVC5 с представлением шаблонов) с включенным методом аутентификации Google. Приложение настроено на прием электронной почты в качестве имени пользователя и на сохранение утверждений, назначенных Google, таких как фамилия, имя, адрес электронной почты, идентификатор имени и т. д., в базу данных участников (AspNetUserClaims).

Когда я регистрируюсь и вхожу под «локальным» пользователем, все в порядке. Если я войду в систему с пользователем Google, все в порядке. Если я вхожу в систему с учетной записью, настроенной как для локального, так и для внешнего входа, я получаю сообщение об ошибке ниже.

Я попытался изменить тип токена на другие настройки, используя параметр AntiForgeryConfig в Application_Start (пример)

AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.Email;

Но кажется, что все претензии дублируются при объединении локальных и внешних логинов. Самое странное, что сбор претензий (на который, как я полагал, был ответ) идентичен для комбинированного и только внешнего логина.

При входе в систему как локальный пользователь эти претензии назначаются

[0]: {http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier: a71ff9c0-8dc4-478b-a6f1-2c4cc34b1e46}
[1]: {http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name: [email protected]}
[2]: {http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider: ASP.NET Identity}

При входе в систему только с удаленной или комбинированной учетной записью список претензий выглядит следующим образом.

[0]: {http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier: 4ab33d77-c2a0-4eff-a759-5cca4323ecbf}
[1]: {http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name: [email protected]}
[2]: {http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider: ASP.NET Identity}
[3]: {http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier: https://www.google.com/accounts/o8/id?id=AitOGoogleIdentifierRemovedForPrivacygwgwgw}
[4]: {http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress: [email protected]}
[5]: {http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname: Other}
[6]: {http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname: Some}
[7]: {http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name: Some Other Person}

Любая помощь будет высоко ценится!

Ошибка и трассировка стека следующие:

Server Error in '/' Application.

Sequence contains more than one matching element

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.InvalidOperationException: Sequence contains more than one matching element

Source Error:


Line 10: @using (Html.BeginForm())
Line 11: {
Line 12:     @Html.AntiForgeryToken()
Line 13:
Line 14:     <div class="form-horizontal">

Source File: x:\someweb\Views\someEntity\Create.cshtml    Line: 12

Stack Trace:


[InvalidOperationException: Sequence contains more than one matching element]
System.Linq.Enumerable.SingleOrDefault(IEnumerable`1 source, Func`2 predicate) +2533810
System.Web.Helpers.AntiXsrf.ClaimUidExtractor.GetUniqueIdentifierParameters(ClaimsIdentity claimsIdentity, String uniqueClaimTypeIdentifier) +701
System.Web.Helpers.AntiXsrf.ClaimUidExtractor.ExtractClaimUid(IIdentity identity) +186
System.Web.Helpers.AntiXsrf.TokenValidator.GenerateFormToken(HttpContextBase httpContext, IIdentity identity, AntiForgeryToken cookieToken) +242
System.Web.Helpers.AntiXsrf.AntiForgeryWorker.GetTokens(HttpContextBase httpContext, AntiForgeryToken oldCookieToken, AntiForgeryToken& newCookieToken, AntiForgeryToken& formToken) +174
System.Web.Helpers.AntiXsrf.AntiForgeryWorker.GetFormInputElement(HttpContextBase httpContext) +109
System.Web.Helpers.AntiForgery.GetHtml() +146
System.Web.Mvc.HtmlHelper.AntiForgeryToken() +39
ASP._Page_Views_Bruker_Create_cshtml.Execute() in x:\prosjekter\Laudi\TFS\Laudi\IWeb\Inspector\Inspector\Views\Bruker\Create.cshtml:12
System.Web.WebPages.WebPageBase.ExecutePageHierarchy() +271
System.Web.Mvc.WebViewPage.ExecutePageHierarchy() +120
System.Web.WebPages.StartPage.RunPage() +63
System.Web.WebPages.StartPage.ExecutePageHierarchy() +100
System.Web.WebPages.WebPageBase.ExecutePageHierarchy(WebPageContext pageContext, TextWriter writer, WebPageRenderingBase startPage) +131
System.Web.Mvc.RazorView.RenderView(ViewContext viewContext, TextWriter writer, Object instance) +695
System.Web.Mvc.BuildManagerCompiledView.Render(ViewContext viewContext, TextWriter writer) +382
System.Web.Mvc.ViewResultBase.ExecuteResult(ControllerContext context) +431
System.Web.Mvc.ControllerActionInvoker.InvokeActionResult(ControllerContext controllerContext, ActionResult actionResult) +39
System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilterRecursive(IList`1 filters, Int32 filterIndex, ResultExecutingContext preContext, ControllerContext controllerContext, ActionResult actionResult) +116
System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilterRecursive(IList`1 filters, Int32 filterIndex, ResultExecutingContext preContext, ControllerContext controllerContext, ActionResult actionResult) +529
System.Web.Mvc.ControllerActionInvoker.InvokeActionResultWithFilters(ControllerContext controllerContext, IList`1 filters, ActionResult actionResult) +106
System.Web.Mvc.Async.<>c__DisplayClass28.<begininvokeaction>
b__19() +321
System.Web.Mvc.Async.<>c__DisplayClass1e.<begininvokeaction>
b__1b(IAsyncResult asyncResult) +185
System.Web.Mvc.Async.WrappedAsyncResult`1.CallEndDelegate(IAsyncResult asyncResult) +42
System.Web.Mvc.Async.WrappedAsyncResultBase`1.End() +133
System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +56
System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeAction(IAsyncResult asyncResult) +40
System.Web.Mvc.Controller.<beginexecutecore>
b__1d(IAsyncResult asyncResult, ExecuteCoreState innerState) +34
System.Web.Mvc.Async.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult) +70
System.Web.Mvc.Async.WrappedAsyncResultBase`1.End() +139
System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +59
System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +40
System.Web.Mvc.Controller.EndExecuteCore(IAsyncResult asyncResult) +44
System.Web.Mvc.Controller.<beginexecute>
b__15(IAsyncResult asyncResult, Controller controller) +39
System.Web.Mvc.Async.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult) +62
System.Web.Mvc.Async.WrappedAsyncResultBase`1.End() +139
System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +59
System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +40
System.Web.Mvc.Controller.EndExecute(IAsyncResult asyncResult) +39
System.Web.Mvc.Controller.System.Web.Mvc.Async.IAsyncController.EndExecute(IAsyncResult asyncResult) +39
System.Web.Mvc.MvcHandler.<beginprocessrequest>
b__4(IAsyncResult asyncResult, ProcessRequestState innerState) +39
System.Web.Mvc.Async.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult) +70
System.Web.Mvc.Async.WrappedAsyncResultBase`1.End() +139
System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +59
System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +40
System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult) +40
System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult result) +38
System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +9688704
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +155

person Lars Thomas Bredland    schedule 16.12.2013    source источник
comment
Параметр AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.Email; в методе Application _Start решил проблему для меня. Спасибо, что задали вопрос.   -  person Jesse Seger    schedule 18.07.2014


Ответы (1)


Поведение нормальное, как видно из следующего метода (вызывается при создании удостоверения пользователя):

await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie)

в методе SignInAsync. В реализации CreateIdentityAsync:

...         
ClaimsIdentity claimsIdentity = new ClaimsIdentity(authenticationType, this.UserNameClaimType, this.RoleClaimType);
claimsIdentity.AddClaim(new Claim(this.UserIdClaimType, user.Id, "http://www.w3.org/2001/XMLSchema#string"));
claimsIdentity.AddClaim(new Claim(this.UserNameClaimType, user.UserName, "http://www.w3.org/2001/XMLSchema#string"));
claimsIdentity.AddClaim(new Claim("http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider", "ASP.NET Identity", "http://www.w3.org/2001/XMLSchema#string"));
if (manager.SupportsUserRole)
{
    foreach (string rolesAsync in await manager.GetRolesAsync(user.Id))
    {
        claimsIdentity.AddClaim(new Claim(this.RoleClaimType, rolesAsync, "http://www.w3.org/2001/XMLSchema#string"));
    }
}
if (manager.SupportsUserClaim)
{
    claimsIdentity.AddClaims(await manager.GetClaimsAsync(user.Id));
}
...

Как видите, по умолчанию добавлено три утверждения. К ним добавляются ваши "кастомные" претензии. Вот почему у вас будут повторяющиеся утверждения, а это означает, что SingleOrDefault вызов коллекции утверждений вызовет ошибку, о которой вы упомянули. В качестве решения вы можете либо использовать другие утверждения, либо обновить их после создания удостоверения, это зависит от потребностей вашего бизнеса.

person Adi Bilauca    schedule 02.01.2014
comment
Означает ли это, что мне нужно вручную проверить Claimscollection, чтобы убедиться, что существует только одно утверждение, соответствующее AntiForgeryConfig.UniqueClaimTypeIdentifier? - person Lars Thomas Bredland; 05.01.2014
comment
Да, вы должны убедиться, что у вас нет повторяющихся утверждений (в основном проверка должна выполняться против тех 3, которые добавляются вручную в CreateIdentityAsync). - person Adi Bilauca; 05.01.2014