web-dev-qa-db-ja.com

MVC 5 Owin Facebook認証でNull参照例外が発生する

Visual Studio 2013の新しいMVC 5プロジェクトで、統合されたOWIN Facebook認証をセットアップしようとしています。このチュートリアルに従って、アプリとキーを構成しました。

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

ただし、AccountControllerのこの呼び出しからNullReferenceExceptionがスローされます。

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

私はすでにFiddlerで応答を確認し、Facebookから成功応答のように見えるものを取得していますが、それでもこのエラーが発生します。応答は次のようになります。

{"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"}

Httpとhttpsでデバッグするときにこれを取得します。これはフレームワークのバグだと思いますが、これまでのところ、リフレクターを介してこれを診断する空白を描いています。

27
Gracie

これはおそらく、アイデンティティOWIN拡張コードのバグです。私のFacebookペイロードは常にjsonのユーザー名フィールドを返すため、問題を再現できません。これはfbレスポンスにありません。なぜそこにないのかよくわかりません。

Identity owin拡張メソッドのコードには、ユーザー名フィールドと同じIDの名前クレームのnullチェックがありません。内部的にバグを報告しました。

この問題を回避するには、ExternalLoginCallbackメソッドを次のコードに置き換えてみてください。

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

Facebook/googleからユーザー名が返されない場合、コードはデフォルトのユーザー名を空に設定します。

26
Hongye Sun

Hongye Sunは、上記の答えですべての重荷を持ち上げました。

コントローラークラスに追加して、面倒なAuthenticationManager.GetExternalLoginInfoAsync()の代わりに呼び出すことができるコードを次に示します。

private async Task<ExternalLoginInfo> AuthenticationManager_GetExternalLoginInfoAsync_Workaround()
{
    ExternalLoginInfo loginInfo = null;

    var result = await AuthenticationManager.AuthenticateAsync(DefaultAuthenticationTypes.ExternalCookie);

    if (result != null && result.Identity != null)
    {
        var idClaim = result.Identity.FindFirst(ClaimTypes.NameIdentifier);
        if (idClaim != null)
        {
            loginInfo = new ExternalLoginInfo()
            {
                DefaultUserName = result.Identity.Name == null ? "" : result.Identity.Name.Replace(" ", ""),
                Login = new UserLoginInfo(idClaim.Issuer, idClaim.Value)
            };
        }
    }
    return loginInfo;
}
24
Bryan Knox

同じ問題がありました。 Startup.Auth.csにapp.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);を追加したばかりの問題を解決しました。 Startup.Auth.csにはありませんでした。

var result = await SignInManager.ExternalSignInAsync(loginInfo, isPersistent: false);

オブジェクトエラーのインスタンスに設定されていないオブジェクト参照が常にスローされます。 MVC 5のVS 2013のデフォルトテンプレートを分析することにより、コード構造またはサンプルに関する詳細情報が必要な場合は、VS 2013 MVC5テンプレートをご覧ください。

4
Daniil T.

ライブラリをチェックしたときに、Microsoft ASP.NET Identity Owin 1.0.0を使用していたときに同じ問題に直面しました。コマンドPM> Install-Package Microsoft.AspNet.Identity.Owinを使用してMicrosoft ASP.NET Identity Owin 2.0.1に更新しました。 -バージョン2.0.1これにより問題が修正されました。

2
Rahul Patel

数日前にこの投稿に出くわしましたが、残念ながら上記のソリューションはどれもうまくいきませんでした。これが私がどうやってそれを修正してFacebookからメールを受け取ることができたかです。

  • 次のNuGet Pacakges を更新
    • _Microsoft.Owin_からバージョン_3.1.0-rc1_へ
    • _Microsoft.Owin.Security_からバージョン_3.1.0-rc1_へ
    • _Microsoft.Owin.Security.Cookies_からバージョン_3.1.0-rc1_へ
    • _Microsoft.Owin.Security.OAuth_からバージョン_3.1.0-rc1_へ
    • _Microsoft.Owin.Security.Facebook_からバージョン_3.1.0-rc1_へ

次に、以下のコードを_Identity Startup_クラスに追加します

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

これは、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);
    }
}
_
2
user3012760

スタックトレースにDotNetOpenAuth.AspNetが含まれている場合、それはDotNetOpenAuth/DotNetOpenIdに2年間存在していると思われるバグと同じです。

DotNetOpenAuthのNullReferenceException

https://github.com/DotNetOpenAuth/DotNetOpenAuth/issues/317#issuecomment-29580565

それらのライブラリの所有者は、MSがそれらを放棄したことを示していますが、おそらく実際にはMSコードに移動されているように欠陥から見えます。

もしそうなら、それはOSSがクローズドコードに埋もれたということですか?

あなたのスタックトレースを見てみたいです。

2
shannon

これを最新のVS 2013.3テンプレートで取得し始め、他のプロジェクトの1つから不必要に移植したFormsAuthenticationで認証がNiceを再生していないことに気付きました。これを修正するために私がやったことは次のとおりです。

追加<system.web><authentication mode="None" />...

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

1
parliament

Google+ APIを有効にしておらず、フィドラーを見たときにaccess_deniedで戻ってきました。 Google+ APIを有効にして問題を解決しました。

0
Liam

同じチュートリアルに従ってもまったく同じ問題がありました。次の2つの手順を実行して解決しました。1> Visual Studioメニュー->ツール->ライブラリパッケージマネージャー->ソリューション用のNuGetパッケージの管理...、インストールパッケージ:Microsoft.Owin.Host.SystemWeb 2>ウィンドウで、[更新](左のバー)をクリックし、すべてのパッケージを更新します。

この答えが同じ問題を抱えている他の人々の助けになることを願っています。

0
Leona

私は同じを得ていました。

プロバイダーが構成されていることに気付きましたbeforeUseExternalSignInCookieが呼び出されたため、プロバイダーが構成され、すべてが機能する前にUseExternalSignInCookieが呼び出されることを確認しました。

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

// This must come later
app.UseGoogleAuthentication(
            "[ClientId]",
            "[ClientSecret]");
0
joshcomley

Visual Studio 2015テンプレートのいくつかのメモ/ WebAPI 2の最新の定型コードを投げると思いました。Google認証でこの問題が発生していましたが、facebookやその他のソーシャルログインに似ています。私は最新のOwinを持っていて、他のnugetパッケージは最新でした。最新のすぐに使用可能なWeb API 2テンプレートで判明したため、Googleから返される「電子メール」を明確に要求する必要がありました。この行がないと、api/Account/Register呼び出しはエラーになります。

そしてもちろん、あなたのアプリがグーグルに登録されていて、あなたのサイトがそれを呼び出すことを許可されていることを確認してください。 (これらの手順を示す良い例がたくさんあります。) https://console.developers.google.com/apis

App_Start\Startup.Auth.csファイルでの調整は次のとおりです。

var googleOptions = new GoogleOAuth2AuthenticationOptions()
{
    ClientId = "xxx",
    ClientSecret = "xxx"
};
googleOptions.Scope.Add("email"); //!! Add this !!
app.UseGoogleAuthentication(googleOptions);

.Add( "email")行を追加するまで、api/Account/RegisterExternal WebAPI 2呼び出し(AccountController.cs)は、RegisterExternalのこのセクションからnullを返します。

var info = await Authentication.GetExternalLoginInfoAsync();
if (info == null) //This would be true, and it would error.
{
      return InternalServerError();
}

これは、このエラーについて出てくる数少ない記事の1つであるため、後世のためにソリューションにメモをタグ付けすることにしました。 (特に郵便配達員のテストプロセス!)

すべてをテストで機能させるには、次のようにします。1)api/Account/ExternalLogins URLを次のように呼び出します。

http://localhost:59137/api/Account/ExternalLogins?returnUrl=%2F&generateState=true

次のような応答が返されます。

<ArrayOfExternalLoginViewModel xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/TCG_DL_API.Models">
<ExternalLoginViewModel>
<Name>Google</Name>
<State>1phegLF241xeSfd8gZAsCXiBAp3l5bMygg2VSeRXAHk1</State>
<Url>
/api/Account/ExternalLogin?provider=Google&response_type=token&client_id=self&redirect_uri=http%3A%2F%2Flocalhost%3A59137%2F&state=1phegLF241xeSfd8gZAsCXiBAp3l5bMygg2VSeRXAHk1
</Url>
</ExternalLoginViewModel>
</ArrayOfExternalLoginViewModel>

2)次に、応答からURLを取得して呼び出します。 Googleログインプロンプト/ページを取得する必要があります。 (または、もしそれがあなたが設定したものであるならば、私はfacebookまたはTwitterのものを仮定します。)

3)ログインすると、リダイレクトページにリダイレクトされます。次のようなURLがあります。

HTTP:// localhostを:59137 /#access_tokenは=d5asC1arCUXaLEMgBS8PT_uwZcTJqC1UZbXblNZ3hMOh3TSKtEXYeKtyKBTv3WmLcaLGGomSvpRSFMfXPxpPvNRgjUVWAiqxtKfv3qWHNqfIMeu5j0eZrJDRAMTrYFgflSbEopAe909a31I4mQnJuvaiITHYPrLmqkm6J88HAVx8F981_q_tflu4A72k3KaB-m2wd0-p1jdQnNMlixM2Wfloh_niUTBIOYUPc1SkKWcZxuI6dzN2Z0PmWHDwzJI8nM8vOuzybJIsxLOyTY1VfzSQ5Qzcll3HhifLPkyZxvXDQ5LHqW1v0_AztsUWkEhW_AJzmw2IaOcTtHCmkmWm1K444okNtOsYfs6HFui0NeY&TOKEN_TYPE=ベアラ&expires_in = 1209600&状態= 3FSOd3_n_sEL4QtiELWPG5B2_H3wRjVb75uDjQS16gk1

トークン(上記の太字)を取得し、ベアラートークンとして使用します。

Postman example of GET api/Account/UserInfo

4)登録されていないので(ただし、ベアラートークンはあります)、POST api/Account/RegisterExternalを呼び出すことができます

enter image description here

5)応答はOKで、AspnetUserテーブルを見ると、プロバイダーとしてgoogleの新しいAspnetUsersレコードと新しいAspNetUserLoginsレコードがあることがわかります。

これがこのようなものを機能させようとしている人に役立つことを願っています!

0
Greg