MVC 5 Owin Facebook Auth results in Null Reference

2019-01-09 00:39发布

I'm trying to setup integrated OWIN Facebook authentication in a new MVC 5 project in Visual Studio 2013. I have configured apps and keys as per this tutorial:

http://www.asp.net/mvc/tutorials/mvc-5/create-an-aspnet-mvc-5-app-with-facebook-and-google-oauth2-and-openid-sign-on

However, I'm getting a NullReferenceException thrown from this call in the AccountController:

    [AllowAnonymous]
    public async Task<ActionResult> ExternalLoginCallback(string returnUrl)
    {
        var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync();

I already checked the response in Fiddler and am getting what appears to be a success response from Facebook, but still get this error. The response looks like this:

{"id":"xxx","name":"xxx","first_name":"xxx","last_name":"xxx","link":
"https:\/\/www.facebook.com\/profile.php?id=xxx","location":{"id":"xxx","name":"xxx"},
"gender":"xxx","timezone":1,"locale":"en_GB","verified":true,"updated_time":"2013-10-23T10:42:23+0000"}

I get this when debugging in http as well as https. I'm guessing this is a framework bug but have so far drawn a blank diagnosing this through reflector.

11条回答
聊天终结者
2楼-- · 2019-01-09 01:17

I started getting this in the latest VS 2013.3 template and realized the authentication wasn't playing nice with FormsAuthentication that I unnecessarily ported from one of my other projects. Here's what I did to fix it:

added <system.web><authentication mode="None" />...

added <system.webServer><modules><remove name="FormsAuthentication" /></modules>...

查看更多
不美不萌又怎样
3楼-- · 2019-01-09 01:21

I faced the same problem, when I checked libraries, I was using Microsoft ASP.NET Identity Owin 1.0.0 I updated it to Microsoft ASP.NET Identity Owin 2.0.1 using command PM> Install-Package Microsoft.AspNet.Identity.Owin -Version 2.0.1 This fixed the issue.

查看更多
Summer. ? 凉城
4楼-- · 2019-01-09 01:22

I came across this post a few days ago but unfortunately none of the above solutions worked for me. so here is how I managed to fix it and get the email from Facebook.

  • Update following NuGet Pacakges
    • Microsoft.Owin to version 3.1.0-rc1
    • Microsoft.Owin.Security to version 3.1.0-rc1
    • Microsoft.Owin.Security.Cookies to version 3.1.0-rc1
    • Microsoft.Owin.Security.OAuth to version 3.1.0-rc1
    • Microsoft.Owin.Security.Facebook to version 3.1.0-rc1

Then add the following code to the Identity Startup class

var facebookOptions = new FacebookAuthenticationOptions()
        {
            AppId = "your app id",
            AppSecret = "your app secret",
            BackchannelHttpHandler = new FacebookBackChannelHandler(),
            UserInformationEndpoint = "https://graph.facebook.com/v2.8/me?fields=id,name,email,first_name,last_name",
            Scope = { "email" }
        };

        app.UseFacebookAuthentication(facebookOptions);

This is the definition class for FacebookBackChannelHandler():

using System;
using System.Net.Http;

public class FacebookBackChannelHandler : HttpClientHandler
{
    protected override async System.Threading.Tasks.Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request,
        System.Threading.CancellationToken cancellationToken)
    {
        // Replace the RequestUri so it's not malformed
        if (!request.RequestUri.AbsolutePath.Contains("/oauth"))
        {
            request.RequestUri = new Uri(request.RequestUri.AbsoluteUri.Replace("?access_token", "&access_token"));
        }

        return await base.SendAsync(request, cancellationToken);
    }
}
查看更多
爱情/是我丢掉的垃圾
5楼-- · 2019-01-09 01:25

This probably is a bug in identity OWIN extension code. I can't repro the issue as my facebook payload always returns a username field in json, which is missing from your fb response. I am not quite sure why it's not there.

The code in identity owin extension method doesn't have a null check for the identity's name claim which is same as the username field. We have filed a bug for it internally.

In order to workaround this issue, could you try replacing your ExternalLoginCallback method with following code:

   [AllowAnonymous]
    public async Task<ActionResult> ExternalLoginCallback(string returnUrl)
    {
        var result = await AuthenticationManager.AuthenticateAsync(DefaultAuthenticationTypes.ExternalCookie);
        if (result == null || result.Identity == null)
        {
            return RedirectToAction("Login");
        }

        var idClaim = result.Identity.FindFirst(ClaimTypes.NameIdentifier);
        if (idClaim == null)
        {
            return RedirectToAction("Login");
        }

        var login = new UserLoginInfo(idClaim.Issuer, idClaim.Value);
        var name = result.Identity.Name == null ? "" : result.Identity.Name.Replace(" ", "");

        // Sign in the user with this external login provider if the user already has a login
        var user = await UserManager.FindAsync(login);
        if (user != null)
        {
            await SignInAsync(user, isPersistent: false);
            return RedirectToLocal(returnUrl);
        }
        else
        {
            // If the user does not have an account, then prompt the user to create an account
            ViewBag.ReturnUrl = returnUrl;
            ViewBag.LoginProvider = login.LoginProvider;
            return View("ExternalLoginConfirmation", new ExternalLoginConfirmationViewModel { UserName = name });
        }
    }

The code will set default user name as empty when there is no username back from facebook/google.

查看更多
放我归山
6楼-- · 2019-01-09 01:29

I was getting the same.

I noticed that my providers were configured before UseExternalSignInCookie was called, so I simply made sure UseExternalSignInCookie is called before my providers are configured and everything worked:

// This has to go first
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);

// This must come later
app.UseGoogleAuthentication(
            "[ClientId]",
            "[ClientSecret]");
查看更多
登录 后发表回答