web-dev-qa-db-ja.com

ASP.Net Core 2.1登録カスタムClaimsPrincipal

Windows認証アプリを作成していますが、ロールはADではなくカスタムデータベース内にあるため、通常はADでロールを確認するUser.IsInRole()関数をオーバーライドするカスタムClaimsPrincipalを作成しました。

ただし、アプリケーションを実行するときは、CustomClaimsPrincipalではなく、元のコードを使用しているようです。 「プライマリドメインと信頼されたドメインの信頼関係に失敗しました」というエラーが表示されます。

ASP.Net MVC 5では、基本的にここで複製しようとしているカスタムRoleProviderを使用しました。

CustomClaimsPrincipal.cs

public class CustomClaimsPrincipal : ClaimsPrincipal
{
    private readonly ApplicationDbContext _context;

    public CustomClaimsPrincipal(ApplicationDbContext context)
    {
        _context = context;
    }

    public override bool IsInRole(string role)
    {
        var currentUser = ClaimsPrincipal.Current.Identity.Name;

        IdentityUser user = _context.Users.FirstOrDefault(u => u.UserName.Equals(currentUser, StringComparison.CurrentCultureIgnoreCase));

        var roles = from ur in _context.UserRoles.Where(p => p.UserId == user.Id)
                    from r in _context.Roles
                    where ur.RoleId == r.Id
                    select r.Name;
        if (user != null)
            return roles.Any(r => r.Equals(role, StringComparison.CurrentCultureIgnoreCase));
        else
            return false;
    }
}

Startup.cs

        services.AddIdentity<ApplicationUser, IdentityRole>().AddEntityFrameworkStores<ApplicationDbContext>();

        services.AddScoped<ClaimsPrincipal,CustomClaimsPrincipal>();

.Net Coreフレームワークは初めてなので、Startup.csの上記のコードがClaimsPrincipalをオーバーライドする正しい方法であるかどうかはわかりません。

5
user2806570

私はその問題に別の方法で取り組むと思います:ClaimsPrincipalのインスタンスにデータベースと通信させて、それらが特定のロールに属しているかどうかを判断させる代わりに、ClaimsPrincipalを変更して追加しますClaimsPrincipalインスタンスでそれらが属するロール。

そのためには、残念ながら十分に文書化されていない機能を使用します。認証パイプラインは、認証が完了すると、作成されたClaimsPrincipalインスタンスを変換できる拡張ポイントを公開します。これは IClaimsTransformation インターフェースを介して行うことができます。

コードは次のようになります。

public class Startup
{
    public void ConfigureServices(ServiceCollection services)
    {
        // Here you'd have your registrations

        services.AddTransient<IClaimsTransformation, ClaimsTransformer>();
    }
}

public class ClaimsTransformer : IClaimsTransformation
{
    private readonly ApplicationDbContext _context;

    public ClaimsTransformer(ApplicationDbContext context)
    {
        _context = context;
    }

    public async Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
    {
        var existingClaimsIdentity = (ClaimsIdentity)principal.Identity;
        var currentUserName = existingClaimsIdentity.Name;

        // Initialize a new list of claims for the new identity
        var claims = new List<Claim>
        {
            new Claim(ClaimTypes.Name, currentUserName),
            // Potentially add more from the existing claims here
        };

        // Find the user in the DB
        // Add as many role claims as they have roles in the DB
        IdentityUser user = await _context.Users.FirstOrDefaultAsync(u => u.UserName.Equals(currentUserName, StringComparison.CurrentCultureIgnoreCase));
        if (user != null)
        {
            var rolesNames = from ur in _context.UserRoles.Where(p => p.UserId == user.Id)
                        from r in _context.Roles
                        where ur.RoleId == r.Id
                        select r.Name;

            claims.AddRange(rolesNames.Select(x => new Claim(ClaimTypes.Role, x)));
        }

        // Build and return the new principal
        var newClaimsIdentity = new ClaimsIdentity(claims, existingClaimsIdentity.AuthenticationType);
        return new ClaimsPrincipal(newClaimsIdentity);
    }
}

完全な開示のために、TransformAsyncメソッドは認証プロセスが行われるたびに実行されるため、ほとんどの場合、すべてのリクエストで実行されます。つまり、すべてのリクエストでデータベースにクエリを実行して、ログインしているユーザーのロールを取得します。

ClaimsPrincipalの実装を変更するよりもこのソリューションを使用する利点は、ClaimsPrincipaldumbになり、関連付けられないことです。データベースに。認証パイプラインだけがそれを認識します。これにより、たとえば、特定のロールでClaimsPrincipalを更新して、特定のアクションを実行するかどうかを確認し、データベースに関連付けられています。

21