shuhelohelo’s blog

Xamarin.Forms多めです.

ASP.NET CoreでOAuthを試す(2)

前回はGoogleAPI側の設定を行いました.

shuhelohelo.hatenablog.com

今回はアプリケーション側でGoogleのOAuthを利用する手順を説明します.

ExternalLoginCallback action in asp net core - YouTube

EFCoreでDBへ接続(作成)

プロジェクトもDBも新規に作成する場合は以下の記事を参考にして,Identityを導入してDBを作成するところまで行う. Update-DatabaseまでできればOk.

shuhelohelo.hatenablog.com

Microsoft.AspNetCore.Authentication.Googleをインストール

Nugetでインストールします.

f:id:shuhelohelo:20191117152812p:plain

ConfigureServicesへの登録

ここでは前回取得したクライアントIDとシークレットが必要になるので,Google API Consoleのページを開いて「認証情報」タブで確認しておきます.

f:id:shuhelohelo:20191223205602p:plain

Startup.csのConfigureServicesメソッド内に以下を追加します.

            services.AddAuthentication()
                .AddGoogle(options =>
                {
                    options.ClientId = "あなたのクライアントID";
                    options.ClientSecret = "あなたのクライアントシークレット";
                });

機密情報をソースコードに入れたくない場合は,UserSecretを使うと安全に機密情報を扱うことができるのでおすすめです. その場合は以下の記事を参考にしてください.

shuhelohelo.hatenablog.com

同じくStartup.csのConfigureメソッドには以下の内容を追加します.

            app.UseAuthentication();

簡単なログインページを作る

Viewsフォルダの下にAccountフォルダを作って,そこにLogin.cshtmlという名前のRazor Viewを作成します.

f:id:shuhelohelo:20191223210712p:plain

中身はこんな感じにしておきます

@model LoginViewModel

@{
    ViewBag.Title = "User Login";
}

<h1>User Login</h1>

<div class="row">
    <div class="col-md-6">
        <h1>External Login</h1>
        <hr/>
        @{
                <form method="post" asp-action="ExternalLogin" asp-route-returnUrl="@Model.ReturnUrl">
                    <div>
                        @foreach(var provider in Model.ExternalLogins)
                        {
                            <button type="submit" class="btn btn-primary"
                                    name="provider" value="@provider.Name"
                                    title="Login using your @provider.DisplayName account.">
                                @provider.DisplayName
                            </button>
                        }
                    </div>
                </form>
        }
    </div>
</div>

まだ,ViewModelやControllerを作っていないので動きませんが,こんな感じのページが表示される予定です.

f:id:shuhelohelo:20191223210447p:plain

Controllerを作る

Controllersフォルダの下にAccountController.csを作成します.

f:id:shuhelohelo:20191223211822p:plain

1つ目のアクションメソッドであるLoginメソッドは以下のとおりです.

これはページを表示させることが主な役割です.

        [HttpGet]
        [AllowAnonymous]
        [Route("[action]")]
        public async Task<IActionResult> Login()
        {
            LoginViewModel model = new LoginViewModel
            {
                ReturnUrl = "",
                ExternalLogins = (await signInManager.GetExternalAuthenticationSchemesAsync()).ToList()
            };
            return View(model);
        }

この一文ExternalLogins = (await signInManager.GetExternalAuthenticationSchemesAsync()).ToList()でsignInManagerに登録した外部ログインプロバイダを取得します.Startup.csで登録したサービスの分だけここで取得されます.

もう一つアクションメソッドを追加します.こちらはGoogleログインボタンが押されたときのアクションです.

        [AllowAnonymous]
        [HttpPost]
        [Route("[action]")]
        public IActionResult ExternalLogin(string provider, string returnUrl)
        {
            //Google側の認証が終わったらどのURLに遷移させるかを指定している
            var redirectUrl = Url.Action("ExternalLoginCallback", "Account",
                new { ReturnUrl = returnUrl });

            var properties = signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl);

            return new ChallengeResult(provider, properties);//Googleの認証ページが開く

"ExternalLoginCallback"って文字列はなんだよ,というところですが,これは後で説明するとして今はここまで.

あと、このAccountControllerでは以下のようにSignInManagerを受け取るようにしておきます。

       private readonly SignInManager<IdentityUser> _signInManager;

        public AccountController(SignInManager<IdentityUser> signInManager)
        {
            _signInManager = signInManager;
        }

ViewModelを作る

ViewModelsフォルダの中にLoginViewModelを作成します.

f:id:shuhelohelo:20191223214438p:plain

    public class LoginViewModel
    {
        /// <summary>
        /// ユーザーがログイン前にアクセスしたURLを入れる
        /// ログイン完了後にリダイレクトするURL
        /// </summary>
        public string ReturnUrl { get; set; }

        public IList<AuthenticationScheme> ExternalLogins { get; set; }
    }

このpublic IList<AuthenticationScheme> ExternalLoginsに外部ログインプロバイダが入ります.

さて,これでViewとControllerとViewModelが揃ったので動くようになったはずです.

デバッグしてみましょう.以下のようなGoogleのログインページが表示されると思います.

f:id:shuhelohelo:20191223214958p:plain

試しにログインを続行してみると,以下のページが表示され,

f:id:shuhelohelo:20191223215251p:plain

さらに「許可」ボタンを押すと,こうなります.

f:id:shuhelohelo:20191223215325p:plain

これは,

  • Googleアカウントの認証は通った
  • 通ったあと,通ったという結果を自分のサイトでどのように使うかは自分で作る.
  • 通常は,通ったという結果をアプリケーションで受け取ったら,自分のサイトのIdentityの仕組みで新規ユーザーを作成してログイン状態にする

ということで,この外部サービスの認証に通った(または通らなかった)という結果を使って自分のサイトのログイン処理をしなければならないのに,それを行うコールバックが見つからないのでエラーになっている,ということです.

外部サービス認証成功後にコールバックを指定しているのは以下の部分で,ExternalLoginCallbacというメソッドを指定しています.

            var redirectUrl = Url.Action("ExternalLoginCallbac", "Account",
                new { ReturnUrl = returnUrl });

でもまだ作ってないので上記のエラーというわけです.

今回はここまでで,次回は外部サービスの認証結果を受け取って自分のサイトのログイン処理を行うコールバックの部分について書きます.