Blazor Server で ユーザー認証機能の自動生成とコード生成(スキャフォールディング)

Blazor Serverではメールアドレスとパスワードによるユーザー認証機能を自動生成できます。

しかし、自動生成しただけではコードまでは自動的に生成されません。

この記事では、ユーザー認証機能とそのコードの自動生成を行う方法を紹介します。

dotnet new コマンドで BlazorServerプロジェクトを作成する

認証機能を付加したBlazorServerプロジェクトの作成は以下のコマンドで行います。

dotnet new blazorserver -au Individual

-au オプションの引数は以下のものを指定できます。

-au(–auth)オプションに指定可能な値

説明
None 認証は行われません (既定)
ndividual 個別認証です
ndividualB2C Azure AD B2C での個別認証
SingleOrg 単一のテナントに対する組織認証
MultiOrg 複数のテナントに対する組織認証です
Windows Windows 認証

参考URL

https://docs.microsoft.com/ja-jp/dotnet/core/tools/dotnet-new-sdk-templates#blazorserver

自動生成されたユーザー登録画面

個別認証で生成した場合のユーザー情報DB

-au Individual で生成した場合、プロジェクトフォルダ直下にapp.dbが作成され、ここにユーザー情報が格納されます。

app.db には、以下のテーブルが含まれます。

ubuntu@ip-172-31-31-143:~/remoteDir/usefuledge20211023/blazorauthsample$ sqlite3 app.db 
SQLite version 3.31.1 2020-01-27 19:55:54
Enter ".help" for usage hints.
sqlite> .tables
AspNetRoleClaims       AspNetUserLogins       AspNetUsers          
AspNetRoles            AspNetUserRoles        __EFMigrationsHistory
AspNetUserClaims       AspNetUserTokens     

このうち、AspNetUsersテーブルに、ユーザーIDやメールアドレス、暗号化されたパスワードなどが格納されます。

AspNetUsersテーブルの定義は以下の通りです。

sqlite> .head on
sqlite> .mode column
sqlite> pragma table_info('AspNetUsers');
cid         name        type        notnull     dflt_value  pk        
----------  ----------  ----------  ----------  ----------  ----------
0           Id          TEXT        1                       1         
1           AccessFail  INTEGER     1                       0         
2           Concurrenc  TEXT        0                       0         
3           Email       TEXT        0                       0         
4           EmailConfi  INTEGER     1                       0         
5           LockoutEna  INTEGER     1                       0         
6           LockoutEnd  TEXT        0                       0         
7           Normalized  TEXT        0                       0         
8           Normalized  TEXT        0                       0         
9           PasswordHa  TEXT        0                       0         
10          PhoneNumbe  TEXT        0                       0         
11          PhoneNumbe  INTEGER     1                       0         
12          SecuritySt  TEXT        0                       0         
13          TwoFactorE  INTEGER     1                       0         
14          UserName    TEXT        0                       0         
sqlite> 

ユーザー登録すると、以下のようなレコードが格納されます。

sqlite> select * from aspnetusers;
Id                                    AccessFailedCount  ConcurrencyStamp                      Email               EmailConfirmed  LockoutEnabled  LockoutEnd  NormalizedEmail     NormalizedUserName  PasswordHash                                                                          PhoneNumber  PhoneNumberConfirmed  SecurityStamp                     TwoFactorEnabled  UserName          
------------------------------------  -----------------  ------------------------------------  ------------------  --------------  --------------  ----------  ------------------  ------------------  ------------------------------------------------------------------------------------  -----------  --------------------  --------------------------------  ----------------  ------------------
a4cff7d9-185b-40a8-b8c9-d521b94a8b9c  0                  7279bfcc-b974-4db6-8acb-1bdb0964b74a  sxxx7@xxx.com  1               1                           SXXX7@XXX.COM  SXXX7@XXX.COM  AQAAAAEAACcQAAAAEBPeHWT8NH482ZzQJtvQ7Hgt/3xTEHohryvzPbx//gQhVK5yTMPeEfBIjjgPnxgf5A==               0                     PQ7WGLR27FIQ2537Y6DFOQFPMVU45AKI  0                 sxxx7@xxx.com
sqlite> 

NuGetパッケージと dotnet tools のインストール

コード生成のため、以下のNuGetパッケージと dotnet tools をインストールしていきます。

Microsoft.VisualStudio.Web.CodeGeneration.Design

後述するdotnet-aspnet-codegeneratorコマンドが含まれています。

dotnet add package Microsoft.VisualStudio.Web.CodeGeneration.Design

参考URL : NuGet Gallery

https://www.nuget.org/packages/Microsoft.VisualStudio.Web.CodeGeneration.Design/

dotnet-aspnet-codegenerator

dotnet aspnet-codegeneratorコマンドを使うため、インストールしていきます。

dotnet tool install -g dotnet-aspnet-codegenerator

参考URL : dotnet-aspnet-codegenerator

https://docs.microsoft.com/en-us/aspnet/core/fundamentals/tools/dotnet-aspnet-codegenerator?view=aspnetcore-6.0

コード生成に必要な 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.SqlServer
dotnet add package Microsoft.EntityFrameworkCore.Tools

dotnet aspnet-codegenerator コマンドの動作確認(ヘルプ表示)

以下のコマンドを実行して、dotnet aspnet-codegeneratorコマンドが正しく使用できるか確認しましょう。

dotnet aspnet-codegenerator identity -h

正しく使用できる場合、以下のようにコマンドの使い方が表示されます。

Usage: aspnet-codegenerator [arguments] [options]

Arguments:
  generator  Name of the generator. Check available generators below.

Options:
  -p|--project             Path to .csproj file in the project.
  -n|--nuget-package-dir   
  -c|--configuration       Configuration for the project (Possible values: Debug/ Release)
  -tfm|--target-framework  Target Framework to use. (Short folder name of the tfm. eg. net46)
  -b|--build-base-path     
  --no-build               

Selected Code Generator: identity

Generator Options:
  --dbContext|-dc       : Name of the DbContext to use, or generate (if it does not exist).
  --files|-fi           : List of semicolon separated files to scaffold. Use the --listFiles option to see the available options.
  --listFiles|-lf       : Lists the files that can be scaffolded by using the '--files' option.
  --userClass|-u        : Name of the User class to generate.
  --useSqLite|-sqlite   : Flag to specify if DbContext should use SQLite instead of SQL Server.
  --force|-f            : Use this option to overwrite existing files.
  --useDefaultUI|-udui  : Use this option to setup identity and to use Default UI.
  --layout|-l           : Specify a custom layout file to use.
  --generateLayout|-gl  : Use this option to generate a new _Layout.cshtml
  --bootstrapVersion|-b : Specify the bootstrap version. Valid values: '3', '4'. Default is 4.

コード生成可能なファイルリストの表示

コード生成が可能なファイルリストは、以下のコマンドで確認できます。

dotnet aspnet-codegenerator identity -sqlite -dc MyApplication.Data.ApplicationDbContext --listFiles
Building project ...
Finding the generator 'identity'...
Running the generator 'identity'...
File List:
Account._StatusMessage
Account.AccessDenied
Account.ConfirmEmail
Account.ConfirmEmailChange
Account.ExternalLogin
Account.ForgotPassword
Account.ForgotPasswordConfirmation
Account.Lockout
Account.Login
Account.LoginWith2fa
Account.LoginWithRecoveryCode
Account.Logout
Account.Manage._Layout
Account.Manage._ManageNav
Account.Manage._StatusMessage
Account.Manage.ChangePassword
Account.Manage.DeletePersonalData
Account.Manage.Disable2fa
Account.Manage.DownloadPersonalData
Account.Manage.Email
Account.Manage.EnableAuthenticator
Account.Manage.ExternalLogins
Account.Manage.GenerateRecoveryCodes
Account.Manage.Index
Account.Manage.PersonalData
Account.Manage.ResetAuthenticator
Account.Manage.SetPassword
Account.Manage.ShowRecoveryCodes
Account.Manage.TwoFactorAuthentication
Account.Register
Account.RegisterConfirmation
Account.ResendEmailConfirmation
Account.ResetPassword
Account.ResetPasswordConfirmation
RunTime 00:00:05.95

コード自動生成の実行

以下のコマンドで、すべてのコードの自動生成(スキャフォールディング)を実行します。

このコマンドは、SQLiteDBを使用したユーザー認証のコード生成です。

MyApplicationの部分はプロジェクト名に変更してください。

dotnet aspnet-codegenerator identity -sqlite -dc MyApplication.Data.ApplicationDbContext

自動生成対象のファイルを指定する場合は、--filesオプションを使用します。

dotnet aspnet-codegenerator identity -sqlite -dc MyApplication.Data.ApplicationDbContext --files "Account.Register;Account.Login"

‘ApplicationDbContext’ is an ambiguous reference エラーの対処法

dotnet runしたときに、以下のように'ApplicationDbContext' is an ambiguous referenceエラーが発生することがあります。

/home/ubuntu/remoteDir/usefuledge20211023/blazorauthsample/Program.cs(15,31): error CS0104: ‘ApplicationDbContext’ is an ambiguous reference between ‘blazorauthsample.Data.ApplicationDbContext’ and ‘MyApplication.Data.ApplicationDbContext’ [/home/ubuntu/remoteDir/usefuledge20211023/blazorauthsample/blazorauthsample.csproj]

エラーが発生した場合は、Program.csのusing句から、using MyApplication.Data;をコメントアウトしましょう。

using blazorauthsample.Areas.Identity;
using blazorauthsample.Data;
//using MyApplication.Data;

InvalidOperationException: Cannot find the fallback endpoint specified by route values: { page: /_Host, area: }. エラーの対処法

dotnet runしたときに、以下のようにInvalidOperationExceptionが発生することがあります。

InvalidOperationException: Cannot find the fallback endpoint specified by route values: { page: /_Host, area: }.
Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.DynamicPageEndpointMatcherPolicy.ApplyAsync(HttpContext httpContext, CandidateSet candidates)

この場合、プロジェクトファイル(.csprojファイル)の<PropertyGroup><UseRazorSourceGenerator>false</UseRazorSourceGenerator>を追加しましょう。

<PropertyGroup>
  <UseRazorSourceGenerator>false</UseRazorSourceGenerator>
</PropertyGroup>

参考URL

https://github.com/dotnet/aspnetcore/issues/36535

コード自動生成後のプロジェクトフォルダ構成

コード自動生成後は、Areasフォルダなどにコードが生成されます。

.
├── ./App.razor
├── ./Areas
│   └── ./Areas/Identity
│       ├── ./Areas/Identity/Data
│       │   └── ./Areas/Identity/Data/ApplicationDbContext.cs
│       ├── ./Areas/Identity/Pages
│       │   ├── ./Areas/Identity/Pages/Account
│       │   │   ├── ./Areas/Identity/Pages/Account/AccessDenied.cshtml
│       │   │   ├── ./Areas/Identity/Pages/Account/AccessDenied.cshtml.cs
│       │   │   ├── ./Areas/Identity/Pages/Account/ConfirmEmail.cshtml
│       │   │   ├── ./Areas/Identity/Pages/Account/ConfirmEmail.cshtml.cs
│       │   │   ├── ./Areas/Identity/Pages/Account/ConfirmEmailChange.cshtml
│       │   │   ├── ./Areas/Identity/Pages/Account/ConfirmEmailChange.cshtml.cs
│       │   │   ├── ./Areas/Identity/Pages/Account/ExternalLogin.cshtml
│       │   │   ├── ./Areas/Identity/Pages/Account/ExternalLogin.cshtml.cs
│       │   │   ├── ./Areas/Identity/Pages/Account/ForgotPassword.cshtml
│       │   │   ├── ./Areas/Identity/Pages/Account/ForgotPassword.cshtml.cs
│       │   │   ├── ./Areas/Identity/Pages/Account/ForgotPasswordConfirmation.cshtml
│       │   │   ├── ./Areas/Identity/Pages/Account/ForgotPasswordConfirmation.cshtml.cs
│       │   │   ├── ./Areas/Identity/Pages/Account/Lockout.cshtml
│       │   │   ├── ./Areas/Identity/Pages/Account/Lockout.cshtml.cs
│       │   │   ├── ./Areas/Identity/Pages/Account/LogOut.cshtml
│       │   │   ├── ./Areas/Identity/Pages/Account/Login.cshtml
│       │   │   ├── ./Areas/Identity/Pages/Account/Login.cshtml.cs
│       │   │   ├── ./Areas/Identity/Pages/Account/LoginWith2fa.cshtml
│       │   │   ├── ./Areas/Identity/Pages/Account/LoginWith2fa.cshtml.cs
│       │   │   ├── ./Areas/Identity/Pages/Account/LoginWithRecoveryCode.cshtml
│       │   │   ├── ./Areas/Identity/Pages/Account/LoginWithRecoveryCode.cshtml.cs
│       │   │   ├── ./Areas/Identity/Pages/Account/Logout.cshtml
│       │   │   ├── ./Areas/Identity/Pages/Account/Logout.cshtml.cs
│       │   │   ├── ./Areas/Identity/Pages/Account/Manage
│       │   │   │   ├── ./Areas/Identity/Pages/Account/Manage/ChangePassword.cshtml
│       │   │   │   ├── ./Areas/Identity/Pages/Account/Manage/ChangePassword.cshtml.cs
│       │   │   │   ├── ./Areas/Identity/Pages/Account/Manage/DeletePersonalData.cshtml
│       │   │   │   ├── ./Areas/Identity/Pages/Account/Manage/DeletePersonalData.cshtml.cs
│       │   │   │   ├── ./Areas/Identity/Pages/Account/Manage/Disable2fa.cshtml
│       │   │   │   ├── ./Areas/Identity/Pages/Account/Manage/Disable2fa.cshtml.cs
│       │   │   │   ├── ./Areas/Identity/Pages/Account/Manage/DownloadPersonalData.cshtml
│       │   │   │   ├── ./Areas/Identity/Pages/Account/Manage/DownloadPersonalData.cshtml.cs
│       │   │   │   ├── ./Areas/Identity/Pages/Account/Manage/Email.cshtml
│       │   │   │   ├── ./Areas/Identity/Pages/Account/Manage/Email.cshtml.cs
│       │   │   │   ├── ./Areas/Identity/Pages/Account/Manage/EnableAuthenticator.cshtml
│       │   │   │   ├── ./Areas/Identity/Pages/Account/Manage/EnableAuthenticator.cshtml.cs
│       │   │   │   ├── ./Areas/Identity/Pages/Account/Manage/ExternalLogins.cshtml
│       │   │   │   ├── ./Areas/Identity/Pages/Account/Manage/ExternalLogins.cshtml.cs
│       │   │   │   ├── ./Areas/Identity/Pages/Account/Manage/GenerateRecoveryCodes.cshtml
│       │   │   │   ├── ./Areas/Identity/Pages/Account/Manage/GenerateRecoveryCodes.cshtml.cs
│       │   │   │   ├── ./Areas/Identity/Pages/Account/Manage/Index.cshtml
│       │   │   │   ├── ./Areas/Identity/Pages/Account/Manage/Index.cshtml.cs
│       │   │   │   ├── ./Areas/Identity/Pages/Account/Manage/ManageNavPages.cs
│       │   │   │   ├── ./Areas/Identity/Pages/Account/Manage/PersonalData.cshtml
│       │   │   │   ├── ./Areas/Identity/Pages/Account/Manage/PersonalData.cshtml.cs
│       │   │   │   ├── ./Areas/Identity/Pages/Account/Manage/ResetAuthenticator.cshtml
│       │   │   │   ├── ./Areas/Identity/Pages/Account/Manage/ResetAuthenticator.cshtml.cs
│       │   │   │   ├── ./Areas/Identity/Pages/Account/Manage/SetPassword.cshtml
│       │   │   │   ├── ./Areas/Identity/Pages/Account/Manage/SetPassword.cshtml.cs
│       │   │   │   ├── ./Areas/Identity/Pages/Account/Manage/ShowRecoveryCodes.cshtml
│       │   │   │   ├── ./Areas/Identity/Pages/Account/Manage/ShowRecoveryCodes.cshtml.cs
│       │   │   │   ├── ./Areas/Identity/Pages/Account/Manage/TwoFactorAuthentication.cshtml
│       │   │   │   ├── ./Areas/Identity/Pages/Account/Manage/TwoFactorAuthentication.cshtml.cs
│       │   │   │   ├── ./Areas/Identity/Pages/Account/Manage/_Layout.cshtml
│       │   │   │   ├── ./Areas/Identity/Pages/Account/Manage/_ManageNav.cshtml
│       │   │   │   ├── ./Areas/Identity/Pages/Account/Manage/_StatusMessage.cshtml
│       │   │   │   └── ./Areas/Identity/Pages/Account/Manage/_ViewImports.cshtml
│       │   │   ├── ./Areas/Identity/Pages/Account/Register.cshtml
│       │   │   ├── ./Areas/Identity/Pages/Account/Register.cshtml.cs
│       │   │   ├── ./Areas/Identity/Pages/Account/RegisterConfirmation.cshtml
│       │   │   ├── ./Areas/Identity/Pages/Account/RegisterConfirmation.cshtml.cs
│       │   │   ├── ./Areas/Identity/Pages/Account/ResendEmailConfirmation.cshtml
│       │   │   ├── ./Areas/Identity/Pages/Account/ResendEmailConfirmation.cshtml.cs
│       │   │   ├── ./Areas/Identity/Pages/Account/ResetPassword.cshtml
│       │   │   ├── ./Areas/Identity/Pages/Account/ResetPassword.cshtml.cs
│       │   │   ├── ./Areas/Identity/Pages/Account/ResetPasswordConfirmation.cshtml
│       │   │   ├── ./Areas/Identity/Pages/Account/ResetPasswordConfirmation.cshtml.cs
│       │   │   ├── ./Areas/Identity/Pages/Account/_StatusMessage.cshtml
│       │   │   └── ./Areas/Identity/Pages/Account/_ViewImports.cshtml
│       │   ├── ./Areas/Identity/Pages/Error.cshtml
│       │   ├── ./Areas/Identity/Pages/Error.cshtml.cs
│       │   ├── ./Areas/Identity/Pages/Shared
│       │   │   └── ./Areas/Identity/Pages/Shared/_LoginPartial.cshtml
│       │   ├── ./Areas/Identity/Pages/_ViewImports.cshtml
│       │   └── ./Areas/Identity/Pages/_ViewStart.cshtml
│       └── ./Areas/Identity/RevalidatingIdentityAuthenticationStateProvider.cs
├── ./Data
│   ├── ./Data/ApplicationDbContext.cs
│   ├── ./Data/Migrations
│   │   ├── ./Data/Migrations/00000000000000_CreateIdentitySchema.Designer.cs
│   │   ├── ./Data/Migrations/00000000000000_CreateIdentitySchema.cs
│   │   └── ./Data/Migrations/ApplicationDbContextModelSnapshot.cs
│   ├── ./Data/WeatherForecast.cs
│   └── ./Data/WeatherForecastService.cs
├── ./Pages
│   ├── ./Pages/Counter.razor
│   ├── ./Pages/Error.cshtml
│   ├── ./Pages/Error.cshtml.cs
│   ├── ./Pages/FetchData.razor
│   ├── ./Pages/Index.razor
│   ├── ./Pages/Shared
│   │   ├── ./Pages/Shared/_Layout.cshtml
│   │   ├── ./Pages/Shared/_LoginPartial.cshtml
│   │   └── ./Pages/Shared/_ValidationScriptsPartial.cshtml
│   ├── ./Pages/_Host.cshtml
│   ├── ./Pages/_Layout.cshtml
│   ├── ./Pages/_ViewImports.cshtml
│   └── ./Pages/_ViewStart.cshtml
├── ./Program.cs
├── ./Properties
│   └── ./Properties/launchSettings.json
├── ./ScaffoldingReadMe.txt
├── ./Shared
│   ├── ./Shared/LoginDisplay.razor
│   ├── ./Shared/MainLayout.razor
│   ├── ./Shared/MainLayout.razor.css
│   ├── ./Shared/NavMenu.razor
│   ├── ./Shared/NavMenu.razor.css
│   └── ./Shared/SurveyPrompt.razor
├── ./_Imports.razor
├── ./app.db
├── ./appsettings.Development.json
├── ./appsettings.json

終わりに

この記事で自動生成したユーザー認証の各ページは、カスタマイズが可能です。

詳細は以下にまとめていますので、ご覧ください。

BLAZOR SERVER で自動生成したユーザー認証機能の各画面をカスタマイズする方法

参考URL

https://docs.microsoft.com/en-us/aspnet/core/security/authentication/scaffold-identity?view=aspnetcore-6.0&tabs=netcore-cli#scaffold-identity-into-a-razor-project-with-authorization

Blazor のおすすめ本

私もBlazorを用いていくつかウェブアプリを開発しました。フレームワークがとても分かりやすく、簡単にSPAを作れることが楽しいと感じています。

Blazor wasm であればAWS S3のようなウェブホスティングサービスでアプリを公開することもできますし、Blazor Serverアプリであれば簡単に2要素認証を構築できます。

Blazor は現在も開発が進められているフレームワークですので本の情報は少しずつ古くなってしまいますが、全体的・体系的に学ぶには、本はとても有力なツールです。

電子書籍になっていますので、まずは試し読みから始めてはいかがでしょうか。

内容
第1章 Blazorの仕組み
第2章 開発環境
第3章 最初のBlazorアプリ
第4章 コンポーネント
第5章 データバインディング
第6章 イベント処理
第7章 Razor記法
第8章 フォームと検証
第9章 データベースアクセス
第10章 Web APIの活用
第11章 SVGの活用
第12章 JavaScriptとの連携

コメントを残す

メールアドレスが公開されることはありません。