web-dev-qa-db-ja.com

Active Directoryに対してユーザーを認証するときに、ASP.NET Core Authorizationクレームを保存するためのベストプラクティスはありますか?

エンタープライズイントラネットASP.NETCoreMVCアプリケーションを作成しています。ユーザーにActiveDirectoryを使用して認証してもらい、ユーザー認証(クレーム)をApplicationDbContextに保存したい。

目標を達成するには、Microsoft.AspNetCore.IdentityおよびMicrosoft.AspNetCore.Identity.EntityFrameworkCoreを使用する必要があると思います。 Active Directoryに対して認証するときに、ASP.NET Core Authorizationクレームを保存するためのベストプラクティスは何ですか?

次のコードは、パイプライン内から現在のWindowsユーザーセキュリティコンテキスト(現在ログインしているユーザー)にアクセスできるようにします。どういうわけか、関連付けられたMicrosoft.AspNetCore.Identityクレームでユーザーをマップする必要がありますか?

 app.Use(async (context, next) =>
 {
      var identity = (ClaimsIdentity) context.User.Identity;
      await next.Invoke();
 });

助けてくれてありがとう!

15
Will

これに関するベストプラクティスはないと思いますが、多くの選択肢があります。おそらく、あなたが達成しようとしていることについて少し詳しく説明することができますか?これを整理するのに役立つ可能性のあるいくつかのポインタを次に示します。ただの質問...内部でADに対して認証するために何を使用していますか? IdentityServer または同様のものを使用する場合は、オプション4に傾くことをお勧めします。

オプション1-クレームをApplicationUserプロパティとして保存する

まず、クレームは単にキーと値のペアです。これは、次のような構造を作成できることを意味します。

_public class UserClaim 
{
    public string UserName {get; set;}
    public string Key {get; set;}
    public string Value {get; set;}
}
_

これにより、クレームをApplicationUserクラスに保存できます。

オプション2 -UserManagerを使用したクレームの保存

さらに良いことに、ユーザークレームを追加するクラスに_UserManager<ApplicationUser> userManager_を挿入し、適切な値を使用してAddClaim()を呼び出すことにより、組み込みのIDコンポーネントを活用できます。 CoreのDIシステムにより、ランタイムによってアクティブ化される任意のクラスでこれを自由に実行できます。

オプション3-独自のテーブルにクレームを保存する

もう1つのアプローチは、UserClaimクラスをUserNameプロパティで拡張してから、原則の一意の識別子(_User.Identity.Name_)を使用することです。次に、それをApplicationDbContextの_DbSet<UserClaim>_に保存し、ユーザー名でクレームを取得できます。

オプション4-クレームを保存しない

クレームにアクセスする必要があり、それらを保存する必要がない場合(質問からの意図がわかりません)、コントローラーを使用している場合は、Userプロパティにアクセスするのが最善の方法です。クレームを正しく水和する認証サービスを使用している場合。

Userは、アプリにサインインしたユーザーに属するクレームで装飾されており、すべてのコントローラーで使用できます。

それ以外の場合は、ClaimsPrincipleを取得して、その方法でユーザーのクレームにアクセスできます。その場合(コントローラーの外部で)、クラスのコンストラクターに_IHttpContextAccessor accessor_を追加し、_HttpContextAccessor.HttpContext.User_プロパティに移動します。これもClaimsPrincipleです。

4
MisterJames

これが私のアプローチでした:

MyUserクラスを実装する

public class MyUser: IdentityUser
{
}

別の「セキュリティ」DBContextでASP.NetCore DbContextを使用します(独自の機能を担当する制限付きコンテキストを好みます)

public class SecurityDbContext : IdentityDbContext<MyUser>
{
    public SecurityDbContext(DbContextOptions<SecurityDbContext> options)
        : base(options)
    { }
}

クレームトランスフォーマーを作成します。これは、ストアからのクレームをClaimsIdentity(HttpContextのUserオブジェクト)に追加するために使用されます。

public class ClaimsTransformer : IClaimsTransformer
{
    private readonly SecurityDbContext _context;
    private readonly UserManager<MyUser> _userManager;

    public ClaimsTransformer(SecurityDbContext context, UserManager<MyUser> userManager)
    {
        _context = context;
        _userManager = userManager;
    }

    public Task<ClaimsPrincipal> TransformAsync(ClaimsTransformationContext context)
    {
        var identity = context.Principal.Identity as ClaimsIdentity;
        if (identity == null) return Task.FromResult(context.Principal);

        try
        {
            if (context.Context.Response.HasStarted)
                return Task.FromResult(context.Principal);

            var claims = AddClaims(identity);
            identity.AddClaims(claims);
        }
        catch (InvalidOperationException)
        {
        }
        catch (SqlException ex)
        {
            if (!ex.Message.Contains("Login failed for user") && !ex.Message.StartsWith("A network-related or instance-specific error"))
                throw;
        }

        return Task.FromResult(context.Principal);
    }

    private IEnumerable<Claim> AddClaims(IIdentity identity)
    {
        var claims = new List<Claim>();
        var existing = _userManager.Users.Include(u => u.Claims).SingleOrDefault(u => u.UserName == identity.Name);
        if (existing == null) return claims;

        claims.Add(new Claim(SupportedClaimTypes.ModuleName, Constants.ADGroupName));
        claims.AddRange(existing.Claims.Select(c => c.ToClaim()));

        return claims;
    }
}

あなたはstartup.csクラスにいくつかのものを追加する必要があります、私はここに適切なものだけを追加しました:

public void ConfigureServices(IServiceCollection services)
{
    services.AddIdentity<FreightRateUser, IdentityRole>(config =>
            {
                config.User.AllowedUserNameCharacters =
                    "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@\\";
            config.User.RequireUniqueEmail = false;
            config.Cookies.ApplicationCookie.LoginPath = "/Auth/Login";
        })
        .AddEntityFrameworkStores<SecurityDbContext>();
}

Configureメソッドを忘れないでください

public async void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    app.UseIdentity();
}

最後に、適切なユーザー/クレームをIDテーブルに追加するために、いくつかのビューが必要になります。いくつかのアクションを備えたコントローラーがあります(ここには[作成]のみが表示されます)。

    [AllowAnonymous]
    public IActionResult CreateAccess()
    {
        var vm = new AccessRequestViewModel
        {
            Username = User.Identity.Name
        };
        return View(vm);
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    [AllowAnonymous]
    public async Task<IActionResult> CreateAccess(AccessRequestViewModel viewModel)
    {
        if (User == null || !User.Identity.IsAuthenticated) return View("Index");

            var newUser = new MyUser
            {
                UserName = viewModel.Username
            };
            var x = await _userManager.CreateAsync(newUser);
            if (!x.Succeeded)
                return View(ModelState);

            var myClaims = new List<Claim>();
            if (viewModel.CanManageSecurity)
                myClaims.Add(new Claim(SupportedClaimTypes.Security, "SITE,LOCAL"));
            if (viewModel.CanChangeExchangeRates)
                myClaims.Add(new Claim(SupportedClaimTypes.ExchangeRates, "AUD,USD"));
            if (viewModel.CanChangeRates)
                myClaims.Add(new Claim(SupportedClaimTypes.Updates, "LOCAL"));
            if (viewModel.CanManageMasterData)
                myClaims.Add(new Claim(SupportedClaimTypes.Admin, "SITE,LOCAL"));

            await _userManager.AddClaimsAsync(newUser, myClaims);
        }
        return View("Index");
    }

ユーザーが保存され、認証されたページを再度表示すると(インデックス)、クレームトランスフォーマーはクレームをClaimsIdentityにロードし、すべてが正常であるはずです。

注意してください、これは現在のHttpContextユーザー向けであり、現在のユーザーが自分自身にアクセスを許可することを明らかに望まないため、作成内の他のユーザーの作成。

0
Allan Nielsen