简体   繁体   中英

Mvc5 ExternalLoginCallback : “await AuthenticationManager.GetExternalLoginInfoAsync()” fails with “sequence contains more than one element”

Why do i keep getting this error with external login callback. Here is what am doing.

imports

using Microsoft.Owin.Security.MicrosoftAccount;
using Microsoft.Owin.Security;

My AccountController.cs class

.    
.
.
.
.
var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync();
if (loginInfo == null)
{                    
    return RedirectToAction("Login", new { returnUrl = returnUrl});
}
.
.
.
.

My Startup.cs class

.
.
.
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);


        app.UseTwoFactorSignInCookie(DefaultAuthenticationTypes.TwoFactorCookie, TimeSpan.FromMinutes(5));
        //
        app.UseExternalSignInCookie(Microsoft.AspNet.Identity.DefaultAuthenticationTypes.ExternalCookie);
.
.
//https://account.live.com/developers/applications/
        //
        microsoftAuthOptions = new MicrosoftAccountAuthenticationOptions()
        {
            ClientId = "xxxxxxx",
            ClientSecret = "xxxxxxx",
            CallbackPath = new PathString("/callbacks/microsoft"),
            Provider = new MicrosoftAccountAuthenticationProvider()
            {
                OnAuthenticated = (context) =>
                {
                    context.Identity.AddClaim(new System.Security.Claims.Claim("MicrosoftAccountAccessToken", context.AccessToken));

                    return Task.FromResult(0);
                }
            }
        };
        app.UseMicrosoftAccountAuthentication(microsoftAuthOptions);

        //
        twitterAuthOptions = new TwitterAuthenticationOptions()
        {
            ConsumerKey = "xxxxxxxx",
            ConsumerSecret = "xxxxxxx",
            CallbackPath = new PathString("/callbacks/twitter"),
            Provider = new TwitterAuthenticationProvider()
            {
                OnAuthenticated = (context) =>
                {
                    context.Identity.AddClaim(new System.Security.Claims.Claim("TwitterAccessToken", context.AccessToken));

                    return Task.FromResult(0);
                }
            },
            BackchannelCertificateValidator = new CertificateSubjectKeyIdentifierValidator(new[]
                {
                    "A5EF0B11CEC04103A34A659048B21CE0572D7D47", // VeriSign Class 3 Secure Server CA - G2
                    "0D445C165344C1827E1D20AB25F40163D8BE79A5", // VeriSign Class 3 Secure Server CA - G3
                    "7FD365A7C2DDECBBF03009F34339FA02AF333133", // VeriSign Class 3 Public Primary Certification Authority - G5
                    "39A55D933676616E73A761DFA16A7E59CDE66FAD", // Symantec Class 3 Secure Server CA - G4
                    "5168FF90AF0207753CCCD9656462A212B859723B", //DigiCert SHA2 High Assurance Server C‎A 
                    "B13EC36903F8BF4701D498261A0802EF63642BC3" //DigiCert High Assurance EV Root CA
                })
        };
        app.UseTwitterAuthentication(twitterAuthOptions);

        //Configure Facebook External Login
        facebookAuthOptions = new FacebookAuthenticationOptions() {
            AppId = "xxxxxxxx",
            AppSecret = "xxxxxxxx",
            CallbackPath = new PathString("/callbacks/facebook"),
            Provider = new FacebookAuthProvider()
            {
                OnAuthenticated = (context) =>
                {
                    context.Identity.AddClaim(new System.Security.Claims.Claim("FacebookAccessToken", context.AccessToken));

                    foreach (var claim in context.User)
                    {
                        var claimType = string.Format("urn:facebook:{0}", claim.Key);
                        var claimValue = claim.Value.ToString();

                        if (!context.Identity.HasClaim(claimType, claimValue))
                            context.Identity.AddClaim(new System.Security.Claims.Claim(claimType, claimValue, "XmlSchemaString", "Facebook"));
                    }

                    return Task.FromResult(0);
                }
            }
        };
        facebookAuthOptions.Scope.Add("email");
        facebookAuthOptions.Scope.Add("user_about_me");
        facebookAuthOptions.Scope.Add("user_photos");
        facebookAuthOptions.Scope.Add("user_location");
 .
 .
 .
 .

Here is the stack trace:

  [InvalidOperationException: Sequence contains more than one element]
   System.Linq.Enumerable.SingleOrDefault(IEnumerable`1 source) +305
   Microsoft.Owin.Security.<AuthenticateAsync>d__8.MoveNext() +213
   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +99
   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +58
   Microsoft.Owin.Security.<GetExternalLoginInfoAsync>d__a.MoveNext() +189
   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +99
   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +58
   System.Runtime.CompilerServices.TaskAwaiter`1.GetResult() +28
   com.hwr.Controllers.<ExternalLoginCallback>d__37.MoveNext() in C:\Users\Bourne Koloh\Documents\Visual Studio 2015\Projects\com.hwr\com.hwr.mvc5\Controllers\AccountController.cs:804
   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +99
   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +58

Which point here in my code View a print screen

This behavior is similar for google, twitter and facebook. The external authentications seems to go well but the callback throw this exception. I appreciate any suggestions offered.

I can't find the source for GetExternalLoginInfoAsync() (in Microsoft.Owin.Security.AuthenticationManagerExtensions), but decompiling reveals (simplified):

await manager.AuthenticateAsync("ExternalCookie");

Source for AuthenticateAsync() is available on CodePlex , where you will find:

public async Task<AuthenticateResult> AuthenticateAsync(string authenticationType)
{
    return (await AuthenticateAsync(new[] { authenticationType })).SingleOrDefault();
}

public async Task<IEnumerable<AuthenticateResult>> AuthenticateAsync(string[] authenticationTypes)
{
    var results = new List<AuthenticateResult>();
    await Authenticate(authenticationTypes, AuthenticateAsyncCallback, results);
    return results;
}

Tracing through the Authenticate(authenticationTypes, AuthenticateAsyncCallback, results) call gets complicated, but ultimately the SingleOrDefault() error you're seeing is because your authentication configuration is resulting in multiple AuthenticateResult entries for the specified `authenticationType" (specifically, "ExternalCookie").

If you can post more of Startup.cs, we can probably find the exact issue.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM