我在使用社交登錄工作在我們現有的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);
}
}
因爲我沒有看到在調試器中拋出任何錯誤,這其中有我難住了。請讓我知道是否有任何其他代碼需要顯示。任何幫助將不勝感激。謝謝。
你的ExternalLogin方法有一個[AllowAnonymous]屬性嗎?我可以用缺失的這個屬性來重現問題。你也可以通過調試器檢查'provider'參數的值嗎? – 2014-09-24 19:26:48
我確實有那些裝飾方法的屬性,我只是無法在SO的代碼嵌入功能中正確地顯示正確的語法。它正在破壞代碼塊。 – Jimbo 2014-09-24 20:21:10
我抱歉Suhas,因爲我忘記提及LoginProvider參數是Facebook。 – Jimbo 2014-09-25 16:41:14