🕌

ASP.NET Coreで認証付きシングルページアプリケーション環境(React)を作る

2021/10/17に公開約8,400字

概要

ASP.NET Coreを使用し、認証付きのシングルページアプリケーション環境(React)を作成する。
SPAのテンプレートであっても、認証周りはRazorページで行なっているようです。

環境

  • Ubuntu 20.04(WSL2でテスト)
  • .NET 5
  • SQLServer for Linux

前提ソフトウェアのインストール

  • Node.js
  • .NET Core
  • EntityFrameworkCore
  • SQLServer for Linux

Node.jsのインストール

sudo apt install nodejs
sudo apt install npm
nodejs -v
npm -v

.NET Coreのインストール

https://docs.microsoft.com/ja-jp/dotnet/core/install/linux-ubuntu
wget https://packages.microsoft.com/config/ubuntu/20.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
sudo dpkg -i packages-microsoft-prod.deb
rm packages-microsoft-prod.deb

sudo apt-get update; \
  sudo apt-get install -y apt-transport-https && \
  sudo apt-get update && \
  sudo apt-get install -y dotnet-sdk-5.0
  

確認

dotnet --version
//5.0.402

EntityFrameworkCoreのインストール

https://docs.microsoft.com/ja-jp/ef/core/cli/dotnet
dotnet tool install --global dotnet-ef

SQLServer for Linuxのインストール

https://docs.microsoft.com/ja-jp/sql/linux/quickstart-install-connect-ubuntu?view=sql-server-ver15
wget -qO- https://packages.microsoft.com/keys/microsoft.asc | sudo apt-key add -
sudo add-apt-repository "$(wget -qO- https://packages.microsoft.com/config/ubuntu/20.04/mssql-server-2019.list)"

sudo apt-get update
sudo apt-get install -y mssql-server

初期設定を行う(エディションの選択、ライセンスに同意、adminのパスワード設定)

sudo /opt/mssql/bin/mssql-conf setup

起動しておく

sudo systemctl start mssql-server
sudo systemctl enable mssql-server
補足(WSL2で動かしている場合のみ)

WSL2で動かしている場合はSystemdがPID=1ではないのでエラーが起きる
wsl2 genieで検索すれば対処法あり
https://github.com/arkane-systems/wsl-transdebian

ルートで実行

sudo -s
wget -O /etc/apt/trusted.gpg.d/wsl-transdebian.gpg https://arkane-systems.github.io/wsl-transdebian/apt/wsl-transdebian.gpg

chmod a+r /etc/apt/trusted.gpg.d/wsl-transdebian.gpg

cat << EOF > /etc/apt/sources.list.d/wsl-transdebian.list
deb https://arkane-systems.github.io/wsl-transdebian/apt/ $(lsb_release -cs) main
deb-src https://arkane-systems.github.io/wsl-transdebian/apt/ $(lsb_release -cs) main
EOF

apt update
apt install daemonize
apt install -y systemd-genie

実行

genie -s

起動時に実行する(引用:https://qiita.com/I_Tatsuya/items/9f85cdb9adc3adcf1abd)
.profileに追加

if [ "`ps -eo pid,cmd | grep systemd | grep -v grep | sort -n -k 1 | awk 'NR==1 { print $1 }'`" != "1" ]; then
  genie -s
fi
source .profile

SQL Server コマンドライン ツールをインストールする

// curlのインストール
sudo apt-get update 
sudo apt install curl
curl https://packages.microsoft.com/keys/microsoft.asc | sudo apt-key add -
curl https://packages.microsoft.com/config/ubuntu/20.04/prod.list | sudo tee /etc/apt/sources.list.d/msprod.list

ツールのインストール

sudo apt-get update 
sudo apt-get install mssql-tools unixodbc-dev
/// ダイアログが2回出てくるのでyes

Pathを通す

echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.profile
source ~/.profile

ローカル接続とデータベースの確認

sqlcmd -S localhost -U SA
//データベースの一覧
1> Select name from sys.databases;
2> go

//使用するデータベースを選択する
1> use <DatabaseName>
2> go

//テーブルの確認
1> Select name From sys.objects;
2> go

プロジェクトの作成

認証付きTemplateを使用してプロジェクトを作成する

//-au 使う認証の種類 -uld SQLite ではなく LocalDB を使用 -o 出力する場所
dotnet new react -au Individual -uld -o myapp

プロジェクトのトップで必要なパッケージを追加する

cd myapp

dotnet add package Microsoft.EntityFrameworkCore.SqlServer
dotnet add package Microsoft.EntityFrameworkCore.Design

SQLServerにアクセスするパスワードをUserSecretsで設定する

dotnet user-secrets init
dotnet user-secrets set DbPassword <your_password>

application.json 内の ConnectionStringsを変更

"ConnectionStrings": {
    "DefaultConnection": "Server=localhost;Database=myapp;User Id=SA;"
  }

Startup.csのデータベースアクセス文字列部分を変更

Startup.cs
//using Microsoft.Data.SqlClient;

var builder = new SqlConnectionStringBuilder(
	Configuration.GetConnectionString("DefaultConnection")
);
builder.Password= Configuration["DbPassword"];
services.AddDbContext<ApplicationDbContext>(options =>
	options.UseSqlServer(builder.ConnectionString));

フロントエンド部分のパッケージをインストールする

cd ClientApp/
npm install

データベースの更新

ASP.NET Core Identityに必要なテーブルが作成される

実行してエラーが出ないことを確認しておく

dotnet run
dotnet ef database update
// 成功すると認証に必要なデータベースが作成される

(補足)vs code で SqlServer拡張を使用しデータベースの内容を確認する

vs code の拡張機能からSql Serverを検索、インストール
SQL Serverのタブが増えるので
CONNECTIONSの隣の+からconnection stringと名前を入力する

//Connection String
Server=localhost;Database=myapp;User Id=SA;Password=<your_password>

電子メール認証を有効にする

マイクロソフト公式ではSendGridがおすすめされていたのでSendGridを使用する
SendGridのアカウント登録等については説明しません

https://docs.microsoft.com/ja-jp/aspnet/core/security/authentication/accconfirm?view=aspnetcore-5.0&tabs=netcore-cli

認証周りのコードをコードジェネレーターで作成し、修正する

初期設定ではユーザー登録時にメールを送信せず、メール認証できるリンクが表示される。
この設定を変えなければならないが、ログイン周りのファイルはRazor Pageに統合されていており、非表示でコードの編集もできない。
そのため編集が必要なファイルを生成する必要がある。

dotnet-aspnet-codegeneratorのインストール

dotnet tool install -g dotnet-aspnet-codegenerator

プロジェクトにpacakgeを追加する

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.SqlServer
dotnet add package Microsoft.EntityFrameworkCore.Tools

dotnet restore

ファイルを生成する

必要なファイルのみ生成する

dotnet aspnet-codegenerator identity -dc myapp.Data.ApplicationDbContext --files "Account.RegisterConfirmation"

すべてのファイルを生成する

dotnet aspnet-codegenerator identity -dc myapp.Data.ApplicationDbContext

メール認証の設定を変更する

Area/Identity/Pages/Account/RegisterConfirmation.csが生成されるので
以下の用に修正する

RegisterConfirmation.cs
DisplayConfirmAccountLink = false;

SendGridの設定

SendGridをプロジェクトに追加する

dotnet add package SendGrid

必要なクラスを作成する

電子メールキーのクラスを作る

/Services/AuthMessageSenderOptions.cs
namespace myapp.Services
{
    public class AuthMessageSenderOptions
    {
        public string SendGridUser { get; set; }
        public string SendGridKey { get; set; }
    }
}

EmailSenderを実装する

Services/EmailSender.cs
using Microsoft.AspNetCore.Identity.UI.Services;
using Microsoft.Extensions.Options;
using SendGrid;
using SendGrid.Helpers.Mail;
using System.Threading.Tasks;

namespace myapp.Services
{
    public class EmailSender : IEmailSender
    {
        public EmailSender(IOptions<AuthMessageSenderOptions> optionsAccessor)
        {
            Options = optionsAccessor.Value;
        }

        public AuthMessageSenderOptions Options { get; } //set only via Secret Manager

        public Task SendEmailAsync(string email, string subject, string message)
        {
            return Execute(Options.SendGridKey, subject, message, email);
        }

        public Task Execute(string apiKey, string subject, string message, string email)
        {
            var client = new SendGridClient(apiKey);
            var msg = new SendGridMessage()
            {
                From = new EmailAddress("your_mail_address", Options.SendGridUser),
                Subject = subject,
                PlainTextContent = message,
                HtmlContent = message
            };
            msg.AddTo(new EmailAddress(email));

            // Disable click tracking.
            // See https://sendgrid.com/docs/User_Guide/Settings/tracking.html
            msg.SetClickTracking(false, false);

            return client.SendEmailAsync(msg);
        }
    }
}

SendGridのユーザーとApiKeyを設定する

dotnet user-secrets set SendGridUser <userName>
dotnet user-secrets set SendGridKey <key>

SendGridの設定をスタートアップで行う

Startup.cs
    // requires
    // using Microsoft.AspNetCore.Identity.UI.Services;
    // using myapp.Services;
    services.AddTransient<IEmailSender, EmailSender>();
    services.Configure<AuthMessageSenderOptions>(Configuration);

ユーザー登録してメールが送信されていれば完了です

おわりに

MVCやWebAPIであっても大まかな流れは同じだと思います
MySQL等でも接続文字列やEntityFrameworkをMySQL用にすればいけそうかも

Discussion

ログインするとコメントできます