.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>()
しかし、なぜSignInManager
にIUserStore
が必要なのか、そしてUserStore
とDBContext
とEntityFramework
ストア、それを使用しない場合(私のGoogleログイン用)?
つまり、問題は、EntityframeworkストアなしでGoogleログインを行うこともできますか?
Googleにサインインするだけの場合は、SignInManager
、UserManager
、または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つのアクションに分解してみましょう。
Login
Login
アクションに到達するために、ユーザーはチャレンジされます。これは、ユーザーがApplication
スキームを使用してサインインしていないが、Authorize
属性(または同様のもの)によって保護されているページにアクセスしようとしている場合に発生します。要件に従って、ユーザーがサインインしていない場合は、Googleを使用してサインインします。これを達成するために、今回はGoogle
スキームに対してnewチャレンジを発行します。そのためには、ChallengeResult
スキームで構成されたGoogle
と、RedirectUrl
を使用します。このLoginCallback
は、Googleログインプロセスが完了すると、独自のアプリケーションコードに戻るために使用されます。コードが示すように、我々はに戻ります:
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固有の処理は、AddAuthentication
のConfigureServices
のAddGoogle
の呼び出しによって構成されます。ログインのためにGoogleにリダイレクトした後、実際にアプリケーションで/signin-google
に戻ります。繰り返しになりますが、これはExternal
の呼び出しのおかげで処理されますが、このコードは実際には、LoginCallback
スキームでCookieを発行し、Googleから返されたクレームを格納して、構成したAddFacebook
エンドポイントにリダイレクトしています。 AuthenticateAsync
への呼び出しを追加すると、/sigin-facebook
エンドポイントが同様のことを行うように構成されます。 ClaimsPrincipal
の呼び出しは、実際には、たとえば、クレームを取得するための/signin-google
エンドポイント。
また、Google/Facebookのサインインプロセスは OAuth 2 protocol に基づいているので、それ自体が一般的なものであることにも注意してください。 Google以外のサポートが必要な場合は、例で行ったようにGoogleにハードコーディングするのではなく、必要なスキームに対してチャレンジを発行するだけです。 LoginCallback
エンドポイントに到達したときに使用されたプロバイダーを判別できるように、チャレンジに追加のプロパティを追加することもできます。
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/