ASP.NET Core

ASP.NET Core Razor Pages と Firebase Authentication を組み合わせた認証機能の作成

2022年2月6日

タイトルのままです。ASP.NET Core Razor Pages と Firebase Authentication を組み合わせた認証機能の作成方法を紹介します。

本稿の完成形サンプルはこちらです。

ASP.NET Core Razor Pages プロジェクト作成

プロジェクト名を付けます。

認証機能は無しで OK です。

ログインページの追加

Pages フォルダ配下に Login.cshtml を追加します。

また、ヘッダーに、Login.cshtml へのリンクを追加する。_Layout.cshtml を、次の様に編集する。

_Layout.cshtml

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@ViewData["Title"] - ASPNETCore_Firebase_Auth_Google</title>
    <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
    <link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
    <link rel="stylesheet" href="~/ASPNETCore_Firebase_Auth_Google.styles.css" asp-append-version="true" />
</head>
<body>
    <header>
        <nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
            <div class="container">
                <a class="navbar-brand" asp-area="" asp-page="/Index">ASPNETCore_Firebase_Auth_Google</a>
                <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target=".navbar-collapse" aria-controls="navbarSupportedContent"
                        aria-expanded="false" aria-label="Toggle navigation">
                    <span class="navbar-toggler-icon"></span>
                </button>
                <div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
                    <ul class="navbar-nav flex-grow-1">
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-page="/Index">Home</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-page="/Privacy">Privacy</a>
                        </li>
                        @*追加*@
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-page="/Login">Login</a>
                        </li>
                    </ul>
                </div>
            </div>
        </nav>
    </header>
    <div class="container">
        <main role="main" class="pb-3">
            @RenderBody()
        </main>
    </div>

    <footer class="border-top footer text-muted">
        <div class="container">
            &copy; 2022 - ASPNETCore_Firebase_Auth_Google - <a asp-area="" asp-page="/Privacy">Privacy</a>
        </div>
    </footer>

    <script src="~/lib/jquery/dist/jquery.min.js"></script>
    <script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
    <script src="~/js/site.js" asp-append-version="true"></script>

    @await RenderSectionAsync("Scripts", required: false)
</body>
</html>

認証機能呼び出し UI の実装

Firebase SDK を利用して、ボタンクリックで Google での認証を呼び出す機能を実装します。実装は大きく分けて、次のことを行っています。

  1. Firebase SDK の読み込み
  2. Firebase アプリケーションの初期化
  3. Google の認証画面の呼び出し

なお、変数 firebaseConfig に含まれる情報は、Firebase の「プロジェクトの概要」>「アプリ(n個のアプリ)」>アプリケーションのギアアイコン > 「全般」>「マイアプリ」>「SDK の設定と構成」に記載のある設定情報を反映します。

Login.cshtml

@page
@model ASPNETCore_Firebase_Auth_Google.Pages.LoginModel
@{
}

<input id="loginButton" type="button" onclick="login()" value="ログイン" />

@section Scripts {
    @*Firebase SDK の読み込み*@
    <script src="https://www.gstatic.com/firebasejs/8.6.2/firebase-app.js"></script>
    <script src="https://www.gstatic.com/firebasejs/8.5.0/firebase-auth.js"></script>
 
    <script>
      //Firebase の設定情報
      const firebaseConfig = {
        apiKey: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
        authDomain: "xxxxxxxxxxxxxxxxxxxxxxxxxx",
        databaseURL: "https://xxxxxxxxxxxxxxxxxxxxxxxxx",
        projectId: "xxxxxxxxxx",
        storageBucket: "xxxxxxxxxxxxxxxxxxxxxx",
        messagingSenderId: "xxxxxxxxxxxx",
        appId: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
      };

    // Firebase アプリケーションの初期化
    firebase.initializeApp(firebaseConfig);
 
    // 認証プロバイダとして、Google の認証機能を利用する
    var provider = new firebase.auth.GoogleAuthProvider();

    // 認証機能の呼び出し
    firebase.auth().getRedirectResult()
      .then((result) => {
        // Google での認証後に呼び出される。result には認証情報が含まれる。
        // ログインしたユーザー情報
        var user = result.user;
        
      }).catch((error) => {
        // エラー処理
      });

	function login() {
        // Google の認証画面にリダイレクトする。
        firebase.auth().signInWithRedirect(provider);
      }
    </script>
}

=> ここまでで、Firebase Authentication を組み込むことができました。

Cookie を利用してサーバー側でログイン状態を維持する

Program.cs を次の様に編集し、Cookie を用いて認証状態を維持できるようにします。

Program.cs

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddRazorPages();

//追加
builder.Services.AddAuthentication("MyCookieAuth").AddCookie("MyCookieAuth", options => {
    options.Cookie.Name = "MyCookieAuth";
});

var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthentication();//追加
app.UseAuthorization();

app.MapRazorPages();

app.Run();

Login.cshtml を次の様に編集し、Firebase Authentication から返却される認証情報から、token と uid を Login.cshtml.cs に送信できるようにします。

Login.cshtml

@page
@model ASPNETCore_Firebase_Auth_Google.Pages.LoginModel
@{
}

<form id="form1" method="post" hidden>
    <input id="token" asp-for="Credential.Token" />
    <input id="uid" asp-for="Credential.Uid" />
</form>
<input id="loginButton" type="button" onclick="login()" value="ログイン" />

@section Scripts {
    @*Firebase SDK の読み込み*@
    <script src="https://www.gstatic.com/firebasejs/8.6.2/firebase-app.js"></script>
    <script src="https://www.gstatic.com/firebasejs/8.5.0/firebase-auth.js"></script>
 
    <script>
        //Firebase の設定情報
      const firebaseConfig = {
        ...
      };

      // Firebase アプリケーションの初期化
    firebase.initializeApp(firebaseConfig);
 
    // 認証プロバイダとして、Google の認証機能を利用する
    var provider = new firebase.auth.GoogleAuthProvider();

    // 認証機能の呼び出し
    firebase.auth().getRedirectResult()
      .then((result) => {
          // Google での認証後に呼び出される。result には認証情報が含まれる。
          
          // ログインしたユーザー情報
          //var user = result.user;
          
          document.getElementById("token").value = result.credential.idToken;
          document.getElementById("uid").value = result.user.uid;
              
          // サーバーに認証情報を送信
          document.getElementById("form1").submit();
      }).catch((error) => {
        // エラー処理
      });

	function login() {
        firebase.auth().signInWithRedirect(provider); // Google の認証画面にリダイレクトする。
      }
    </script>
}

続いて、Login.cshtml.cs を次の様に編集し、Login.cshtml から送られてくる token と uid を元に ClaimsPrincipal を作成し、HttpContext.SignInAsync メソッドを呼び出すことで、ASP.NET Core アプリケーション上でログインとします。

Login.cshtml.cs

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using System.Security.Claims;
using Microsoft.AspNetCore.Authentication;

namespace ASPNETCore_Firebase_Auth_Google.Pages
{
    public class LoginModel : PageModel
    {
        [BindProperty]
        public Credential Credential { get; set; }

        public void OnGet()
        {
        }

        public async Task<IActionResult> OnPost()
        {
            if (!ModelState.IsValid)
            {
                return Page();
            }

            if (Credential == null)
            {
                return Page();
            }

            var claims = new List<Claim>()
            {
                new Claim(ClaimTypes.UserData, Credential.Token),
                new Claim(ClaimTypes.NameIdentifier, Credential.Uid)
            };

            var identity = new ClaimsIdentity(claims, "MyCookieAuth");
            ClaimsPrincipal claimsPrincipal = new ClaimsPrincipal(identity);

            await HttpContext.SignInAsync("MyCookieAuth", claimsPrincipal);

            return RedirectToPage("/Index");
        }
    }

    public class Credential
    {
        public string Token { get; set; }
        public string Uid { get; set; }
    }
}

=> Login.cshtml 上の「ログイン」ボタンをクリックすると、Login.cshtml.cs の OnPost メソッドが呼び出され、Index.cshtml にリダイレクトされます。リダイレクト後、Index.cshtml.cs にて、User.Identity.IsAuthenticated の値が true となっていること、MyAuthCookie が生成されていることが確認できます。UI 上にログインユーザー向けの機能を表示する場合、User.Identity.IsAuthenticated で判定すれば OK です。

サンプル(再掲)

-ASP.NET Core