27

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 でデバッグするときに発生します。これはフレームワークのバグだと思いますが、これまでのところ、リフレクターを介してこれを診断する空白を描いています。

4

11 に答える 11

26

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

ID 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 から返されたユーザー名がない場合、コードはデフォルトのユーザー名を空に設定します。

于 2013-10-24T17:57:30.340 に答える
24

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;
}
于 2013-12-30T20:59:48.973 に答える
4

私も同じ問題を抱えていました。app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create); Startup.Auth.csに追加したばかりの問題を解決します。私の Startup.Auth.cs にはそれがなかったので

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

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

于 2014-10-20T17:03:10.470 に答える
2

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

DotNetOpenAuth の NullReferenceException

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

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

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

スタック トレースを参照してください。

于 2013-12-02T05:55:48.127 に答える
2

ライブラリをチェックしたときに同じ問題に直面しました。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 これにより、問題が修正されました。

于 2014-07-06T10:06:00.077 に答える
1

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

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

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

于 2014-08-30T00:41:54.387 に答える
0

Visual Studio 2015 テンプレート/WebAPI 2 の最新のボイラー プレート コードについていくつかのメモを書き留めておこうと思いました。Google 認証でこの問題が発生していましたが、Facebook やその他のソーシャル ログインに似ていると考えました。私は最新の Owin を持っていて、他の nuget パッケージは最新でした。最新のすぐに使える web api 2 テンプレートが判明しました。「メール」を Google から返すように具体的に要求する必要がありました。この行がないと、api/Account/Register の呼び出しでエラーが発生します。

そしてもちろん、アプリが Google に登録されていることと、サイトがアプリを呼び出すことが許可されていることを確認してください。(これらの手順を示す良い例がたくさんあります。) 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 =bearer&expires_in=1209600&state=3FSOd3_n_sEL4QtiELWPG5B2_H3wRjVb75uDjQS16gk1

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

Postman の GET api/Account/UserInfo の例

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

ここに画像の説明を入力

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

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

于 2016-03-02T08:42:18.183 に答える
0

私は同じことをしていました。

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

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

// This must come later
app.UseGoogleAuthentication(
            "[ClientId]",
            "[ClientSecret]");
于 2015-12-07T04:07:46.720 に答える