我使用Asp.Net MVC 5,并利用Microsoft的Identity(v2)实现进行身份验证和外部(facebook)登录。
我的外部登录代码如下:
在Startup.Auth.cs中,我声明提供者:
var facebookAuthenticationOptions = new FacebookAuthenticationOptions();
facebookAuthenticationOptions.Scope.Add("email");
(...)
facebookAuthenticationOptions.AppId = "<my fb app id>";
facebookAuthenticationOptions.AppSecret = "<my fb app secret>";
facebookAuthenticationOptions.Provider = new FacebookAuthenticationProvider()
{
OnAuthenticated = async context =>
{
//Get the access token from FB and store it in the database
context.Identity.AddClaim(
new System.Security.Claims.Claim("FacebookAccessToken",
context.AccessToken));
}
};
app.UseFacebookAuthentication(facebookAuthenticationOptions);
在我发布facebook登录表单的控制器功能中,
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult ExternalLogin(string provider, string returnUrl)
{
returnUrl = !String.IsNullOrEmpty(returnUrl) ? returnUrl : "/";
// Request a redirect to the external login provider
return new ChallengeResult(provider, Url.Action("ExternalLoginCallback", "Account", new { ReturnUrl = returnUrl }));
return null;
}
在我的基本控制器中(我从中获得所有控制器),我使用owin OAuth:
internal 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;
}
context.HttpContext.GetOwinContext().Authentication.Challenge(properties, LoginProvider);
}
}
然后,我用一个外部回调函数获得回调(正如我在上面的ChalangeResult对象中声明的那样):
[AllowAnonymous]
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 result = await SignInManager.ExternalSignInAsync(loginInfo, isPersistent: false);
switch (result)
{
// login logic code here.
// and return some View(""); or RedirerctToAction("somewhere");
}
}
另外值得注意的是,我使用StructureMap 3.0进行依赖注入,根据下面的代码,它将任何控制器代码的生命周期限制为请求的生命周期。
public void Init(HttpApplication context) {
context.BeginRequest += (sender, e) => StructuremapMvc.StructureMapDependencyScope.CreateNestedContainer();
context.EndRequest += (sender, e) => {
HttpContextLifecycle.DisposeAndClearAll();
StructuremapMvc.StructureMapDependencyScope.DisposeNestedContainer();
};
}
现在,这一切都工作得很好,当我从chrome运行应用程序时,确实为我处理了facebook登录。但当我使用internet explorer(尝试11)或firefox时,它会挂在/{controller}/ExternalLogin的黑屏中,并且不进行任何重定向。
如果这是国际奥委会对结构图控制的问题,我相信它在铬上也不应该顺利运行。所以我一直在网上搜索,找不到解决方案,也找不到任何关于发生了什么的迹象。由于我没有得到任何例外或类似的情况,我不知道自己做错了什么。
综上所述:
- 我使用的是:ASP.NET MVC 5+OWIN(v3.0.1)+Identity(v2)+StructureMap 3+Facebook登录
- 这一切都很好用铬
- 在IE11或Firefox中不起作用
- 我的问题是(1)为什么?以及(2)我该如何解决这个问题
谢谢。
好吧,我想的有点太复杂了。问题出在我发布的输入标签上。
如果你的post操作是采用像public ActionResult ExternalLogin(string provider, string returnUrl)
这样的表单数据(即没有模型),并且你使用输入图像的名称和值来提供表单操作,比如:
<input type="image" id="@facebookLogin.AuthenticationType" name="provider" value="@facebookLogin.AuthenticationType"...>
然后,由于某种原因,Chrome会发送正确的帖子数据,而internet explorer和firefox则不能。
因此,没有依赖性注入、中间件或OAuth问题,只有这个简单的旧html。