🎉

BlazorでWindows認証と独自認証を組み合わせる

2024/06/22に公開

やりたいこと

  • Blazor(Server)でWindows認証を使用したうえで、認証・承認は独自で行いたい。

前提

前回作ったやつの続きを想定。
https://zenn.dev/nmiura_thakaz/articles/b3a6b3f3662801

読みにくいので気が向いたら推敲する(しない)。

作業手順

以下の手順に従う。

認証・承認用のDBを追加

今回はローカルでPostgreSQLを用意し、そこにユーザーの情報を入れることにする。

  1. PostgreSQLをインストール
  1. インストールできたらpgadminを開いて確認。

Blazor側

EntityFrameworkとPostgreSQLを利用する。

  1. NuGetで必要なパッケージをインストールする。
  • Microsoft.EntityFrameworkCore
  • Microsoft.EntityFrameworkCore.Design
  • Microsoft.EntityFrameworkCore.Tools
  • Npgsql.EntityFrameworkCore.PostgreSQL

  1. 適当なフォルダを作りモデルを追加する。
User.cs
//using省略

namespace Windows認証テスト.Model
{
    [Table("users"),Comment("ログイン管理用")]
    public class User
    {
    [Column("user_id"), Comment("ユーザーID")]
        [Key]
        public string Id { get; set; }
        /// <summary>
        /// 権限   0:一般ユーザ  1: 管理者の想定
        /// </summary>
        [Column("role"),Comment("権限コード")]
        public int Role { get; set; }
    }
}
  1. 適当なフォルダを作りDbContextを追加する。
TestDbContext.cs
//using省略

namespace Windows認証テスト.DB
{
    public class TestDBContext  : DbContext
    {
        public TestDBContext(DbContextOptions<TestDBContext> options) : base(options)
        {
        }
        public DbSet<User> Users{ get; set; }
    }
}
  1. Program.csappsettings.jsonを編集して接続情報を追加する。
Prgram.cs
+builder.Services.AddDbContextFactory<TestDBContext>(opt => {
+    opt.UseNpgsql(
+        builder.Configuration.GetConnectionString("DefaultConnection"),
+        providerOptions =>
+        {
+            providerOptions.EnableRetryOnFailure();
+        });
+});
appsettings.json
+  "ConnectionStrings":
+ {"DefaultConnection":"Host=localhost:5432;Database=testdb;Username=postgres;Password=パスワード"  }

実際にはセキュリティ的に環境変数とかで設定したほうが?

  1. コードからテーブルを作る。

https://learn.microsoft.com/ja-jp/ef/core/managing-schemas/migrations/?tabs=dotnet-core-cli

PowerShellから

dotnet ef migrations add InitialCreate

を実行すると、Migrationsフォルダができる。

dotnet ef database update

でデータベースとテーブルが作られる。

Role認証のあれこれ

  1. ロール情報の追加

Windows認証ができたらDBからロール情報を取得しセットする。
Program.csに以下を追加し、独自のClaimsTransformation.csを作成する。

builder.Services.AddDbContextFactory<TestDBContext>(opt =>
{
    opt.UseNpgsql(
        builder.Configuration.GetConnectionString("DefaultConnection"),
        providerOptions =>
        {
            providerOptions.EnableRetryOnFailure();
        });
});

+ builder.Services.AddScoped<IClaimsTransformation,CustomClaimsTransformation>();

適当な場所に

CustomClaimsTransformation.cs
//using省略
namespace Windows認証テスト
{
    public class CustomClaimsTransformation : IClaimsTransformation
    {
        private readonly IDbContextFactory<TestDBContext> _dbFactory;

        public CustomClaimsTransformation(IDbContextFactory<TestDBContext> dbFactory)
        {
            _dbFactory = dbFactory;
        }

        public Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
        {
            var identity = (ClaimsIdentity)principal.Identity;

            var newIdentity = new ClaimsIdentity(identity.Claims, identity.AuthenticationType);

            //DBから取得したロール情報を追加
            using (var db = _dbFactory.CreateDbContext())
            {
                var user = db.Users.FirstOrDefault(u => u.UserId == identity.Name);

                if (user != null)
                {
                    //とりあえず1ならAdmin、それ以外はUserとする
                   // identity.AddClaim(new Claim(ClaimTypes.Role, user.Role == 1 ? "Admin" : "User"));
                    newIdentity.AddClaim(new Claim(ClaimTypes.Role, user.Role == 1 ? "Admin" : "User"));
                }
            }
            var newPrincipal = new ClaimsPrincipal(newIdentity);
            principal.AddIdentity(newIdentity);

            return Task.FromResult(principal);
        }
    }
}
試行錯誤メモ

AddNegotiateのoptionを設定すればこの辺が不要になりそうだけど、このoptionが機能するのはkestrelのみっぽい。
https://github.com/dotnet/aspnetcore/issues/21557
発行するど動作が変わる(エラーにはならない)ので大パニック。

  1. Home.razorでロールが正しく機能するか確認。
Home.razor
<AuthorizeView>
        <p>ログインユーザ: @context.User.Identity.Name!</p>
</AuthorizeView>

<AuthorizeView Roles="User">
    <p>Role:User</p>
</AuthorizeView>

<AuthorizeView Roles="Admin">
    <p>Role:Admin </p>
</AuthorizeView>

実際にアクセスしてみる。


よさそう。


参考サイト

https://qiita.com/tom-sato/items/037b8f8cb4b326710f71
https://learn.microsoft.com/ja-jp/ef/core/managing-schemas/migrations/?tabs=dotnet-core-cli

Discussion