最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

c# - How to handle foreign keys to the user table when using Microsoft Entra ID for authentication in ASP.NET Core? - Stack Over

programmeradmin3浏览0评论

I'm integrating Microsoft Entra ID (Azure AD) into my ASP.NET Core application for authentication. Since Entra ID is an external identity provider (SSO), I will no longer store users in my database, meaning I won't have a User entity. However, my existing database schema relies on a User table for foreign key relationships in multiple entities, such as Bot, UserExchange, and VirtualBalance.

Since Entra ID will handle authentication, my application will receive the authenticated user's ID (sub claim from the JWT). However, I won't have a User entity stored in my database anymore, which creates the following problems:

  1. Foreign keys: how do I replace UserId foreign key constraints in related tables now that users won't exist in my database?

  2. Queries & joins: since I no longer have a User entity, how can I query user-related data without breaking existing relationships?

public class User : BaseAuditableEntity
{
    public User(string email, string password)
    {
        Id = Guid.CreateVersion7();
        Email = email;
        Password = password;
    }

    public string Email { get; private set; }
    public string Password { get; private set; }

    public ICollection<UserExchange> UserExchanges { get; } = new List<UserExchange>();
    public ICollection<VirtualBalance> VirtualBalances { get; } = new List<VirtualBalance>();
}

public class Bot : BaseAuditableEntity
{
    // EF Core cannot bind value object in EF constructor: 
    [UsedImplicitly]
    private Bot() { }
    
    public Bot(Guid userId, Guid exchangeId, Pair pair, decimal investment)
    {
        Id = Guid.CreateVersion7();
        UserId = userId;
        ExchangeId = exchangeId;
        Pair = pair;
        Investment = investment;
    }
    
    public Guid UserId { get; private set; }
    public Guid ExchangeId { get; private set; }
    public Pair Pair { get; private set; } = null!;
    public decimal Investment { get; private set; }
    
    public User User { get; private set; } = null!;
    public Exchange Exchange { get; private set; } = null!;
}

public class Exchange : BaseAuditableEntity
{
    public Exchange(string name)
    {
        Id = Guid.CreateVersion7();
        Name = name;
        IsActive = true;
    }

    public string Name { get; private set; }
    public bool IsActive { get; private set; }

    public void Activate()
    {
        IsActive = true;
    }

    public void Deactivate()
    {
        IsActive = false;
    }
}

public class Order : BaseAuditableEntity
{
    // EF Core cannot bind value object in EF constructor: 
    [UsedImplicitly]
    private Order() { }
    
    public Order(Guid botId, Pair pair, OrderSide side, decimal quantity, decimal price, string? clientOrderId = null)
    {
        Id = Guid.CreateVersion7();
        BotId = botId;
        Pair = pair;
        Side = side;
        Status = new OrderState(OrderStatus.New);
        Quantity = quantity;
        Price = price;
        ClientOrderId = clientOrderId;
        CreateOrderPlacedEvent();
    }
    
    public Guid BotId { get; private set; }
    public Pair Pair { get; private set; } = null!;
    public OrderSide Side { get; private set; }
    public OrderState Status { get; private set; } = null!;
    public decimal Quantity { get; private set; }
    public decimal Price { get; private set; }
    public string? ClientOrderId { get; private set; }

    public Bot Bot { get; private set; } = null!;
        
    public void Cancel()
    {
        AddDomainEvent(new OrderCanceledEvent());
        Status = Status.Cancel();
    }

    public void CreateOrderPlacedEvent()
    {
        AddDomainEvent(new OrderPlacedEvent(Bot.Exchange.Name));
    }
}

public class UserExchange
{
    public UserExchange(Guid userId, Guid exchangeId, string apiKey, string secretKey, string? passphrase = null)
    {
        UserId = userId;
        ExchangeId = exchangeId;
        ApiKey = apiKey;
        SecretKey = secretKey;
        Passphrase = passphrase;
    }

    public Guid UserId { get; private set; }
    public Guid ExchangeId { get; private set; }
    public string ApiKey { get; private set; }
    public string SecretKey { get; private set; }
    public string? Passphrase { get; private set; }
    
    public User User { get; private set; } = null!;
    public Exchange Exchange { get; private set; } = null!;
}

public class VirtualBalance : BaseAuditableEntity
{
    public VirtualBalance(string asset, decimal available, decimal locked)
    {
        Id = Guid.CreateVersion7();
        Asset = asset;
        Available = available;
        Locked = locked;
    }

    public string Asset { get; private set; }
    public decimal Available { get; private set; }
    public decimal Locked { get; private set; }
    
    public Guid UserId { get; private set; }
    public User User { get; private set; } = null!;
}
public class UserConfiguration : IEntityTypeConfiguration<User>
{
    public void Configure(EntityTypeBuilder<User> builder)
    {
        builder.ToTable("User", SchemaNames.Settings);
        
        builder.HasKey(x => x.Id);
        builder.Property(x => x.Id).ValueGeneratedOnAdd();
        
        builder.Property(x => x.Email).HasMaxLength(256).IsRequired();
        builder.Property(x => x.Password).HasMaxLength(256).IsRequired();
        builder.Property(x => x.CreatedAt).IsRequired();
        
        builder.HasIndex(x => x.Email).IsUnique();
    }
}

public class UserExchangeConfiguration : IEntityTypeConfiguration<UserExchange>
{
    public void Configure(EntityTypeBuilder<UserExchange> builder)
    {
        builder.ToTable("UserExchange", SchemaNames.Settings);

        builder.HasKey(x => new { x.UserId, x.ExchangeId });

        builder.Property(x => x.UserId).IsRequired();
        builder.Property(x => x.ExchangeId).IsRequired();
        builder.Property(x => x.ApiKey).HasMaxLength(256).IsRequired();
        builder.Property(x => x.SecretKey).HasMaxLength(256).IsRequired();
        builder.Property(x => x.Passphrase).HasMaxLength(256).IsRequired(false);
        
        builder.HasOne(x => x.User)
            .WithMany(x => x.UserExchanges)
            .HasForeignKey(x => x.UserId)
            .OnDelete(DeleteBehavior.Cascade)
            .IsRequired();

        builder.HasOne(x => x.Exchange)
            .WithMany()
            .HasForeignKey(x => x.ExchangeId)
            .OnDelete(DeleteBehavior.Cascade)
            .IsRequired();
        
        builder.HasIndex(x => new { x.UserId, x.ExchangeId }).IsUnique();
    }
}

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论