web-dev-qa-db-ja.com

entityframeworkプロバイダーなしで.netコアにGoogleログインを実装する方法

.netコアサイトにGoogleログインを実装しています。

このコードでは

var properties = signInManager.ConfigureExternalAuthenticationProperties("Google", redirectUrl);      
return new ChallengeResult("Google", properties); 

私はsignInManagerが必要です(これはコード例による)。

private SignInManager<AppUser> signInManager;

コンストラクタを介して挿入すると、次のエラーが発生します。

「AccountController」をアクティブにしようとしているときに、タイプ「Microsoft.AspNetCore.Identity.SignInManager1 [AppUser]」のサービスを解決できません。

グーグルは、これを含める必要があることを学びました

services.AddIdentity<AppUser, IdentityRole>()
    .AddDefaultTokenProviders();`

しかし、それは私にこのエラーを与えます:

「Microsoft.AspNetCore.Identity.AspNetUserManager1 [AppUser]」をアクティブ化しようとしているときに、タイプ「Microsoft.AspNetCore.Identity.IUserStore1 [AppUser]」のサービスを解決できません。

そのとき、私はこれを追加するようアドバイスを受けます:

.AddEntityFrameworkStores<ApplicationDbContext>()

しかし、なぜSignInManagerIUserStoreが必要なのか、そしてUserStoreDBContextEntityFrameworkストア、それを使用しない場合(私のGoogleログイン用)?

つまり、問題は、EntityframeworkストアなしでGoogleログインを行うこともできますか?

6
Michel

Googleにサインインするだけの場合は、SignInManagerUserManager、またはASP.NET Core Identity自体は必要ありません。これを実現するには、最初に認証サービスを構成する必要があります。これに関連するコードは次のとおりです。これについては後で説明します。

Startup.cs

services
    .AddAuthentication(o =>
    {
        o.DefaultScheme = "Application";
        o.DefaultSignInScheme = "External";
    })
    .AddCookie("Application")
    .AddCookie("External")
    .AddGoogle(o =>
    {
        o.ClientId = ...;
        o.ClientSecret = ...;
    });
  • AddAuthenticationを呼び出すと、DefaultSchemeが構成され、最終的にApplicationスキームとChallengeスキームの両方として使用されます。 Applicationスキームは、ユーザーを認証しようとするときに使用されます(サインインされていますか?)。 Challengeスキームは、ユーザーがnotにサインインしているが、アプリケーションがサインインするオプションを提供したい場合に使用されます。 DefaultSignInSchemeについては後で説明します。

  • AddCookieへの2つの呼び出しは、Application(ourApplicationscheme)とExternal(ourSignInscheme)の両方にCookieベースの認証スキームを追加します。 AddCookieは、2番目の引数を取ることもできます。対応するクッキーの寿命など.

これを設定すると、チャレンジプロセスはユーザーを/Account/Loginにリダイレクトします(デフォルトでは、これはCookie認証オプションでも設定できます)。チャレンジプロセスを処理するコントローラーの実装は次のとおりです(ここでも後で説明します)。

AccountController.cs

public class AccountController : Controller
{
    public IActionResult Login(string returnUrl)
    {
        return new ChallengeResult(
            GoogleDefaults.AuthenticationScheme,
            new AuthenticationProperties
            {
                RedirectUri = Url.Action(nameof(LoginCallback), new { returnUrl })
            });
    }

    public async Task<IActionResult> LoginCallback(string returnUrl)
    {
        var authenticateResult = await HttpContext.AuthenticateAsync("External");

        if (!authenticateResult.Succeeded)
            return BadRequest(); // TODO: Handle this better.

        var claimsIdentity = new ClaimsIdentity("Application");

        claimsIdentity.AddClaim(authenticateResult.Principal.FindFirst(ClaimTypes.NameIdentifier));
        claimsIdentity.AddClaim(authenticateResult.Principal.FindFirst(ClaimTypes.Email));

        await HttpContext.SignInAsync(
            "Application",
            new ClaimsPrincipal(claimsIdentity));

        return LocalRedirect(returnUrl);
    }
}

これを2つのアクションに分解してみましょう。

  1. Login

    Loginアクションに到達するために、ユーザーはチャレンジされます。これは、ユーザーがApplicationスキームを使用してサインインしていないが、Authorize属性(または同様のもの)によって保護されているページにアクセスしようとしている場合に発生します。要件に従って、ユーザーがサインインしていない場合は、Googleを使用してサインインします。これを達成するために、今回はGoogleスキームに対してnewチャレンジを発行します。そのためには、ChallengeResultスキームで構成されたGoogleと、RedirectUrlを使用します。このLoginCallbackは、Googleログインプロセスが完了すると、独自のアプリケーションコードに戻るために使用されます。コードが示すように、我々はに戻ります:

  2. DefaultSignInScheme

    ここで、AddAuthenticationへの呼び出しからのDefaultSignInSchemeが関連します。 Googleログインプロセスの完了の一部として、ClaimsPrincipalは、Googleから返されたユーザーを表すLoginCallbackを含むCookieの設定に使用されます(これはすべて裏で処理されます)。 ClaimsPrincipalのコードの最初の行は、このAuthenticateResultインスタンスを保持します。このインスタンスは、最初に成功を確認されるClaimsPrincipal内にラップされます。これまでのところすべてが成功している場合、必要なクレーム(この場合はGoogleから取得)を含む新しいClaimsPrincipalを作成し、Applicationスキームを使用してそのSignInManagerにサインインします。最後に、最初のchallengeを引き起こしたページにリダイレクトします。


この回答を書くために作成した完全な例を含むGitHubリポジトリを作成しました ここ


以下のコメントのフォローアップコメント/質問への回答:

UserManagerおよびSignInManagerは、データベースで認証を使用する場合にのみ使用されると結論付けることはできますか?

ある意味では、はい、それは公平だと思います。インメモリストアを実装することは可能ですが、永続性がないため、あまり意味がありません。ただし、状況でこれらのクラスを使用しない本当の理由は、ユーザーを表すためにローカルユーザーアカウントを必要としないからです。これは永続化と密接に関連していますが、区別する価値があります。

そして、本で読んだコード(Googleログインの設定に使用したもの)や、読んだ他のすべての回答とはまったく異なるコードです。

ドキュメントとブックは最も一般的な使用例をカバーしており、doすることができるローカルユーザーをにリンク Googleなどの外部アカウントです。AddIdentityのソースを見ると、上に示した種類のコード(例 here および-)の上にあることがわかります。 ここ )。他のコードは、デフォルトのUI(例 ここ )と AuthenticateAsync にあります。

LoginCallbackがGoogleから呼び出されると思います。 HttpContext.AuthenticateAsyncは、Googleが送信したデータを確認する方法を知っていますか?そして、その名前は非常に一般的であるため、すべての外部プロバイダーに対してその方法を知っているように見えますか?

ここでのAddGoogleの呼び出しは、Googleについて何も知らない-Google固有の処理は、AddAuthenticationConfigureServicesAddGoogleの呼び出しによって構成されます。ログインのためにGoogleにリダイレクトした後、実際にアプリケーションで/signin-googleに戻ります。繰り返しになりますが、これはExternalの呼び出しのおかげで処理されますが、このコードは実際には、LoginCallbackスキームでCookieを発行し、Googleから返されたクレームを格納して、構成したAddFacebookエンドポイントにリダイレクトしています。 AuthenticateAsyncへの呼び出しを追加すると、/sigin-facebookエンドポイントが同様のことを行うように構成されます。 ClaimsPrincipalの呼び出しは、実際には、たとえば、クレームを取得するための/signin-googleエンドポイント。

また、Google/Facebookのサインインプロセスは OAuth 2 protocol に基づいているので、それ自体が一般的なものであることにも注意してください。 Google以外のサポートが必要な場合は、例で行ったようにGoogleにハードコーディングするのではなく、必要なスキームに対してチャレンジを発行するだけです。 LoginCallbackエンドポイントに到達したときに使用されたプロバイダーを判別できるように、チャレンジに追加のプロパティを追加することもできます。

6
Kirk Larkin

Entity Frameworkを使用したくない場合は、カスタムストレージプロバイダーを使用する必要があります。 https://docs.Microsoft.com/en-us/aspnet/identity/overview/extensibility/overview-of-custom- storage-providers-for-aspnet-identity Entity Frameworkを使用したいのに(説明したように)エラーが発生した場合は、私のソースデモを参照できます。

https://bitbucket.org/tuanv2t/net-core-demo/src/master/NetCoreDemo/GoogleLoginDemo/

0
tuanv2t