🔐

VSCodeで既存ASP.NET Core Razor Pagesのプロジェクトに 認証(ASP.NET Core Identity)を追加

2023/07/17に公開

既存ASP.NET Coreのプロジェクトに 認証(ASP.NET Core Identity)を追加する

Asp.net Core Razor Pagesでサンプルアプリを試している中で、最低限の「認証機能」を意識してみました。システムにログインしていなければ、ページを参照できないようにして、ログイン画面に誘導する、をまず実現できるように検討してみます。

動作検証環境

  • .NET SDK 7.0.203
  • SQLite
  • Macbook Air M1

実行環境の準備

チュートリアル: ASP.NET Core で Razor Pages Web アプリを作成する

こちらを参考に、トップページから週報を入力するアプリを作ってみました。このアプリを認証機能としてユーザーログインしていなければ参照・利用できない状態を目指します。

ASP.NET Core の Identity って?

以下ページにて
ASP.NET Core の Identity の概要

  • ユーザー インターフェイス (UI) ログイン機能をサポートする API です。
  • ユーザー、パスワード、プロファイル データ、ロール、要求、トークン、電子メールの確認などを管理します。

と説明があり、これらが標準機能で用意されているので利用しない手はないと思います。今回は、データベースにSQLiteを採用している状態から、ASP.NET Core Identity を取り入れてみます。

追加対応

下記ページを途中まで参考にして、実装していきます。

ASP.NET Core プロジェクトでの Identity のスキャフォールディング

コードジェネレーターの導入

dotnet tool install -g dotnet-aspnet-codegenerator

Nuget Package の追加

dotnet add package Microsoft.VisualStudio.Web.CodeGeneration.Design
dotnet add package Microsoft.EntityFrameworkCore.Design
dotnet add package Microsoft.AspNetCore.Identity.EntityFrameworkCore
dotnet add package Microsoft.AspNetCore.Identity.UI
dotnet add package Microsoft.EntityFrameworkCore.SQLite
dotnet add package Microsoft.EntityFrameworkCore.SqlServer
dotnet add package Microsoft.EntityFrameworkCore.Tools

SQLite 関連のEntityFrameworkCore パッケージについてはすでに導入済み状態となっているので、将来的な拡張の事も考えてSQLServerのパッケージも入れておきます。

Entity Framework Core による Identity データベースマイグレーション

以下のコマンドにて、EFCoreを利用した、認証に関するデータベースマイグレーション情報を使います。

dotnet ef migrations add CreateIdentitySchema

と、思ったら、

More than one DbContext was found. Specify which one to use. Use the '-Context' parameter for PowerShell commands and the '--context' parameter for dotnet commands.

DbContextが複数あるので、そのまま実行できない状態になりました。(以下画像はGitコミットの履歴より)
Untitled

ここでは簡略化も考えて、元々あったDBContextに統合し、DbContextを1つにしてしまいます。ここでは、DBContextのファイル名を RazorShuhouEntryContext.cs としてあります。

Data/RazorShuhouEntryContext.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using RazorShuhouEntry.Models;

namespace RazorShuhouEntry.Data
{
    public class RazorShuhouEntryContext : IdentityDbContext<IdentityUser>
    {
        public RazorShuhouEntryContext (DbContextOptions<RazorShuhouEntryContext> options)
            : base(options)
        {
        }


        public DbSet<RazorShuhouEntry.Models.WeeklyReport> WeeklyReport { get; set; } = default!;
    }
}

再びコマンドを実行します。

dotnet ef migrations add CreateIdentitySchema

ビルドに成功しました。
0 個の警告
0 エラー

うまくいきました。

データベース情報更新

用意したマイグレーション情報でデータベースを更新します。(SQLも書かずに自動でやってしまうのもすごいことだ)

dotnet ef database update

反映内容確認

dotnet ef migrations list

Build started...
Build succeeded.
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (5ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      SELECT COUNT(*) FROM "sqlite_master" WHERE "name" = '__EFMigrationsHistory' AND "type" = 'table';
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (0ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      SELECT "MigrationId", "ProductVersion"
      FROM "__EFMigrationsHistory"
      ORDER BY "MigrationId";
20230709080711_InitialCreate
20230716203813_CreateIdentitySchema

SQLiteにできたデータベース構造確認

Untitled

アプリケーション側の修正

RazorPages の 認証有効化設定

認証機能を試してみます。以下ページを参考
ASP.NET Core での単純な承認

動作のお試しということで、登録内容一覧ページだけを認証対象にしてみます。IndexModelに Authorize 属性 付与。

Pasges/WeeklyReports/Index.cshtml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
using RazorShuhouEntry.Data;
using RazorShuhouEntry.Models;
using Microsoft.AspNetCore.Authorization;

namespace RazorShuhouEntry.Pages.WeeklyReports
{
    [Authorize]
    public class IndexModel : PageModel
    {
        private readonly RazorShuhouEntry.Data.RazorShuhouEntryContext _context;

        public IndexModel(RazorShuhouEntry.Data.RazorShuhouEntryContext context)
        {
            _context = context;
        }
    
    (省略・・)

    }
}

Program.cs の確認

Program.csもどのように書き換わっているかを確認します。

Program.cs
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using RazorShuhouEntry.Data;
using Microsoft.AspNetCore.Identity;
var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddDbContext<RazorShuhouEntryContext>(options =>
    options.UseSqlite(builder.Configuration.GetConnectionString("RazorShuhouEntryContext") ?? throw new InvalidOperationException("Connection string 'RazorShuhouEntryContext' not found.")));

builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true).AddEntityFrameworkStores<RazorShuhouEntryContext>();

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.UseAuthorization();

app.MapRazorPages();

app.Run();

app.UseAuthorization() が、認証を有効化している部分であることがわかります。

実行確認

では、実行確認してみます。デバッグ実行して、トップページの「入力開始」リンクにて画面遷移。トップページは下記のような構造になっています。

Pages/Index.cshtml
@page
@model IndexModel
@{
    ViewData["Title"] = "Home page";
}

<div class="text-center">
    <h1 class="display-4">Welcome</h1>
    <p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
    <a asp-page="./WeeklyReports/index">入力開始</a>
</div>

Untitled
Untitled

無事にシステムにログインしていなければページが表示できない状態を確認できました。ただしこの状態では、ページ遷移のためにブラウザのURLにを直接アドレスを入力してしまった場合は、次の画面に進めてしまうため、追加で考慮が必要な状態であることもわかります。
Untitled

まとめ

チュートリアルに習い動作を確認しているだけなのですが、標準機能としてこれだけの機能が用意されていることが素直にすごいと思います(この手の機能を手組みしていた世代なので・・・)。標準機能に任せられる部分は素直に任せるとして、この段階では、ページが見える、ページが見えない、に過ぎない状態なので、アプリの使用制限ことを考えて、標準機能と追加実装の兼ね合いを意識しつつ、アプリを世の中に公開するに当たって必要な次の手を考えていきます。

GitHubで編集を提案

Discussion