我在使用社交登录在我们现有的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);
}
}
由于我没有看到调试器中出现任何错误,因此我感到难过。如果还有其他需要显示的代码,请告诉我。任何帮助将不胜感激。谢谢。
答案 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
属性对它们进行协调,您可以在上面看到。