IAuthenticationManager.Challenge不调用ExternalLoginCallback

时间:2014-09-24 18:04:27

标签: c# asp.net asp.net-mvc asp.net-identity-2

我在使用社交登录在我们现有的ASP.NET MVC网站项目中工作时遇到问题。普通客户(我们的自定义数据库)登录工作正常。由于某种原因,IAuthenticationManager上的Challenge方法不会重定向到ExternalLoginCallback Action,以便正确的社交登录提供程序可以提示登录。现在,Challenge方法重定向回AccountController登录操作,登录页面加载后的URL如下所示:

http://localhost/Account/Login?ReturnUrl=%2fAccount%2fExternalLogin

我已经在ASP.Net site that pertains to the new Identity API上完成了多个教程。我经历了this tutorial first以了解代码,设置和创建概念证明。然后,我与this tutorial一起将新的Identity API融合到我们现有的网站中,并替换旧的System.Web.Security.MembershipProvider实现。以下是代码的一些快照。

Startup.Auth.cs

public partial class Startup
{
    // For more information on configuring authentication, please visit http://go.microsoft.com/fwlink/?LinkId=301864
    public void ConfigureAuth(IAppBuilder app)
    {
        // Configure the db context and user manager to use a single instance per request
        //app.CreatePerOwinContext(ApplicationDbContext.Create);
        app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);

        // Enable the application to use a cookie to store information for the signed in user
        // and to use a cookie to temporarily store information about a user logging in with a third party login provider
        // Configure the sign in cookie
        app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
            LoginPath = new PathString("/Account/Login"),
            Provider = new CookieAuthenticationProvider
            {
                OnValidateIdentity = SecurityStampValidator
                                    .OnValidateIdentity<ApplicationUserManager, IdentityUser, int>(validateInterval: TimeSpan.FromMinutes(30), 
                                                                                                    regenerateIdentityCallback: (manager, user) => user.GenerateUserIdentityAsync(manager), 
                                                                                                    getUserIdCallback: (id) => (Int32.Parse(id.GetUserId())))
            }
        });

        app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);

        // Uncomment the following lines to enable logging in with third party login providers
        //app.UseMicrosoftAccountAuthentication(
        //    clientId: "",
        //    clientSecret: "");

        //app.UseTwitterAuthentication(
        //   consumerKey: "",
        //   consumerSecret: "");

        FacebookAuthenticationOptions fbAuthenticationOptions = new FacebookAuthenticationOptions();
        fbAuthenticationOptions.Scope.Add("email");
        fbAuthenticationOptions.AppId = "XXXXXX";
        fbAuthenticationOptions.AppSecret = "YYYYYYY";
        fbAuthenticationOptions.Provider = new FacebookAuthenticationProvider()
                                           {
                                               OnAuthenticated = async 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);
                                                       string claimValue = claim.Value.ToString();
                                                       if (!context.Identity.HasClaim(claimType, claimValue))
                                                           context.Identity.AddClaim(new System.Security.Claims.Claim(claimType, claimValue, "XmlSchemaString", "Facebook"));

                                                   }

                                               }
                                           };
        fbAuthenticationOptions.SignInAsAuthenticationType = DefaultAuthenticationTypes.ExternalCookie;
        app.UseFacebookAuthentication(fbAuthenticationOptions);

        //app.UseGoogleAuthentication(new GoogleOAuth2AuthenticationOptions()
        //{
        //    ClientId = "",
        //    ClientSecret = ""
        //});
    }
}

AccountController.cs中的ChallengeResult类

private class ChallengeResult : HttpUnauthorizedResult
{
    public ChallengeResult(string provider, string redirectUri)
        : this(provider, redirectUri, null)
    {
    }

    public ChallengeResult(string provider, string redirectUri, string userId)
    {
        LoginProvider = provider;
        RedirectUri = redirectUri;
        UserId = userId;
    }

    public string LoginProvider { get; set; }
    public string RedirectUri { get; set; }
    public string UserId { get; set; }

    public override void ExecuteResult(ControllerContext context)
    {
        var properties = new AuthenticationProperties() { RedirectUri = RedirectUri };
        if (UserId != null)
        {
            properties.Dictionary[XsrfKey] = UserId;
        }

        IOwinContext owinContext = context.HttpContext.GetOwinContext();
        IAuthenticationManager authenticationManager = owinContext.Authentication;
        try
        {
            authenticationManager.Challenge(properties, LoginProvider);
        }
        catch (Exception ex)
        {
            throw;
        }
    }
}

AccountController.cs中的ExternalLogin

public ActionResult ExternalLogin(string provider, string returnUrl)
{
    // Request a redirect to the external login provider
    return new ChallengeResult(provider, Url.Action("ExternalLoginCallback", "Account", new { ReturnUrl = returnUrl }));
}

AccountController.cs中的ExternalLoginCallBack

public async Task<ActionResult> ExternalLoginCallback(string returnUrl)
{
    var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync();
    if (loginInfo == null)
    {
        return RedirectToAction("Login");
    }

    // Sign in the user with this external login provider if the user already has a login
    var user = await UserManager.FindAsync(loginInfo.Login);
    if (user != null)
    {
        await SignInAsync(user, isPersistent: false);
        return RedirectToLocal(returnUrl);
    }
    else
    {
        // Get the information about the user from the external login provider
        var info = await AuthenticationManager.GetExternalLoginInfoAsync();
        if (info == null)
        {
            return View("ExternalLoginFailure");
        }
        string email = info.ExternalIdentity.Claims.First(c => c.Type == "urn:facebook:email").Value;
        string firstName = info.ExternalIdentity.Claims.First(c => c.Type == "urn:facebook:first_name").Value;
        string lastName = info.ExternalIdentity.Claims.First(c => c.Type == "urn:facebook:last_name").Value;

        // If the user does not have an account, then prompt the user to create an account
        RegisterDisplay registerDisplay = new RegisterDisplay
                                          {
                                              Email = email,
                                              Agree = true,
                                              UserName = loginInfo.DefaultUserName,
                                              MailingAddress = new MailingAddress() { FirstName = firstName, LastName = lastName }
                                          };

        ViewBag.ReturnUrl = returnUrl;
        ViewBag.LoginProvider = loginInfo.Login.LoginProvider;
        TempData["RegisterDisplay"] = registerDisplay;
        return View("Register", returnUrl);
    }
}

由于我没有看到调试器中出现任何错误,因此我感到难过。如果还有其他需要显示的代码,请告诉我。任何帮助将不胜感激。谢谢。

3 个答案:

答案 0 :(得分:8)

好的co-worker我找出了跳过ExternalLoginCallback的Challenge方法的问题。这是一个web.config问题,我忘了用原始问题发帖。我们需要将身份验证模式修改为None。它被用作表格,导致网站劫持挑战电话。

web.config中的原始system.web部分

<system.web>
    <httpRuntime targetFramework="4.5" />
    <compilation debug="true" targetFramework="4.5" />
    <authentication mode="Forms">
        <forms loginUrl="~/Account/Login" timeout="2880" />
    </authentication>
</system.web>

修复了web.config中的system.web部分

<system.web>
    <authentication mode="None" />
    <compilation debug="true" targetFramework="4.5.1" />
    <httpRuntime targetFramework="4.5.1" />
</system.web>

我们还必须将一个删除子项添加到system.webServer模块部分

<system.webServer>
    <modules runAllManagedModulesForAllRequests="true">
      <remove name="FormsAuthenticationModule" />
    </modules>
</system.webServer>

现在一切都正在重定向。

答案 1 :(得分:0)

不确定您的代码究竟出现了什么问题,但请检查以下代码行替换您的代码。几个月前我遇到了同样的问题,原因是在添加facebook app凭证之前添加了电子邮件范围。

        var facebookOptions = new FacebookAuthenticationOptions()
        {
            AppId = "FacebookAppId",
            AppSecret = "FacebookAppSecret"
        };
        facebookOptions.Scope.Add("email");

        // Add your claims, provider details here.

        app.UseFacebookAuthentication(facebookOptions);

希望这有帮助。

答案 2 :(得分:0)

就我而言,挑战只是返回401 (Unauthorized)

HttpContext.GetOwinContext().Authentication.Challenge("Application")

要使其正常运行,我必须将其更改为:

HttpContext.GetOwinContext().Authentication.Challenge(DefaultAuthenticationTypes.ApplicationCookie)

因为这是我在Startup上配置Cookie身份验证的方式:

app.UseCookieAuthentication(new CookieAuthenticationOptions
{
    AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie, // <---- I have to pass the same value as `AuthenticationType` to the `Challenge` method
    AuthenticationMode = AuthenticationMode.Passive,
    LoginPath = new PathString("/Account/Login"),
    Provider = cookieAuthenticationProvider
});

Challenge方法仅适用于已注册的身份验证方法,它通过已配置的AuthenticationType属性对它们进行协调,您可以在上面看到。

相关问题