2014-09-24 60 views
4

我在使用社交登錄工作在我們現有的ASP.NET MVC網站項目中遇到問題。普通客戶(我們的自定義數據庫)登錄工作得很好。出於某種原因,IAuthenticationManager上的Challenge方法不會重定向到ExternalLoginCallback Action,以便正確的社交登錄提供程序可以提示登錄。眼下的挑戰方法登錄頁面加載後重定向回的AccountController登錄行動和URL看起來像這樣:IAuthenticationManager.Challenge不會調用ExternalLoginCallback

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 = "" 
     //}); 
    } 
} 

ChallengeResult類內部的在AccountController.cs

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

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; 
     } 
    } 
} 

ExternalLogin

ExternalLoginCallBack在AccountController.cs

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); 
    } 
} 

因爲我沒有看到在調試器中拋出任何錯誤,這其中有我難住了。請讓我知道是否有任何其他代碼需要顯示。任何幫助將不勝感激。謝謝。

+0

你的ExternalLogin方法有一個[AllowAnonymous]屬性嗎?我可以用缺失的這個屬性來重現問題。你也可以通過調試器檢查'provider'參數的值嗎? – 2014-09-24 19:26:48

+0

我確實有那些裝飾方法的屬性,我只是無法在SO的代碼嵌入功能中正確地顯示正確的語法。它正在破壞代碼塊。 – Jimbo 2014-09-24 20:21:10

+0

我抱歉Suhas,因爲我忘記提及LoginProvider參數是Facebook。 – Jimbo 2014-09-25 16:41:14

回答

7

好的a co-worker我想通過挑戰方法跳過ExternalLoginCallback的問題。這是一個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> 

我們還必須添加刪除子系統。webServer模塊部分

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

現在一切都重定向,因爲它應該。

+0

這真的很有幫助,但我遇到的一件事是在web.config中,它應該是:,而不是。 – DavidS 2015-05-06 02:10:10

0

不確定你的代碼有什麼問題,但請檢查下面的代碼行來替換你的代碼。幾個月前我有類似的問題,原因是在添加Facebook應用程序憑證之前添加電子郵件範圍。

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

     // Add your claims, provider details here. 

     app.UseFacebookAuthentication(facebookOptions); 

希望這會有所幫助。

+0

我很欣賞這次改變的努力,但沒有運氣。我仍然看到相同的行爲。 – Jimbo 2014-09-24 20:31:49