You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于ASP.NET Identity实现多用户独立卡牌收藏系统的方案咨询

绝对适合!ASP.NET Identity 就是为这类用户数据隔离场景量身打造的

没错,ASP.NET Identity 完全能满足你的需求——它自带成熟的用户注册、登录、身份验证体系,而且天然支持将业务数据与用户ID绑定,实现不同用户数据完全隔离的效果,就像你说的Gmail那种机制。

接下来我基于你给出的现有模型,一步步给你落地的实现方案:

第一步:给业务模型添加用户关联

首先要让Card和Deck都与ASP.NET Identity的用户(默认是ApplicationUser)建立关联,这样每张卡牌、每个卡组都能明确归属到某个用户。修改你的模型:

修改后的Card类

public class Card {
    public int Id { get; set; }
    public string Name { get; set; }
    public int? Atk { get; set; }
    public int? Def { get; set; }
    public string Desc {get; set;}
    public int? Level { get; set; }
    public string Type { get; set; }
    public string Attribute { get; set; }
    
    // 添加用户关联字段
    public string UserId { get; set; }
    public virtual ApplicationUser User { get; set; }
    
    [DisplayName("Image")]
    public virtual List<Image> Card_Images { get; set; }
    public virtual List<Deck> Decks { get; set; }
}

修改后的Deck类

public class Deck {
    public int Id { get; set; } // 统一成大写Id符合C#命名规范
    public string Name { get; set; }
    public string Notes { get; set; }
    
    // 添加用户关联字段
    public string UserId { get; set; }
    public virtual ApplicationUser User { get; set; }
    
    [DisplayName("Card")]
    public virtual List<Card> Cards { get; set; } // 改成复数Cards更符合语义
}

第二步:配置DbContext中的关系

在你的DbContext(比如AppDbContext)中,需要配置这些关联关系,确保EF Core能正确生成数据库表和外键:

public class AppDbContext : IdentityDbContext<ApplicationUser>
{
    public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }

    public DbSet<Card> Cards { get; set; }
    public DbSet<Deck> Decks { get; set; }
    public DbSet<Image> Images { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder); // 必须调用,确保Identity表正常生成

        // 配置Card与User的关系:一个用户拥有多个卡牌
        modelBuilder.Entity<Card>()
            .HasOne(c => c.User)
            .WithMany(u => u.Cards) // 需要在ApplicationUser中添加对应导航属性
            .HasForeignKey(c => c.UserId)
            .OnDelete(DeleteBehavior.Cascade); // 用户删除时,关联卡牌一并删除

        // 配置Deck与User的关系:一个用户拥有多个卡组
        modelBuilder.Entity<Deck>()
            .HasOne(d => d.User)
            .WithMany(u => u.Decks) // 需要在ApplicationUser中添加对应导航属性
            .HasForeignKey(d => d.UserId)
            .OnDelete(DeleteBehavior.Cascade);

        // 配置Deck与Card的多对多关系,自动生成中间关联表
        modelBuilder.Entity<Deck>()
            .HasMany(d => d.Cards)
            .WithMany(c => c.Decks)
            .UsingEntity(j => j.ToTable("DeckCards"));
    }
}

别忘了在ApplicationUser类中添加对应的导航属性:

public class ApplicationUser : IdentityUser
{
    public virtual List<Card> Cards { get; set; } = new List<Card>();
    public virtual List<Deck> Decks { get; set; } = new List<Deck>();
}

第三步:修改数据访问逻辑,确保用户只能访问自己的数据

在你的控制器或服务层中,所有查询、添加、修改操作都要带上当前登录用户的ID,过滤出属于自己的数据:

示例:CardController中的查询与创建逻辑

public class CardController : Controller
{
    private readonly AppDbContext _context;
    private readonly UserManager<ApplicationUser> _userManager;

    public CardController(AppDbContext context, UserManager<ApplicationUser> userManager)
    {
        _context = context;
        _userManager = userManager;
    }

    // 只显示当前用户的卡牌
    public async Task<IActionResult> Index()
    {
        var currentUserId = _userManager.GetUserId(User);
        var userCards = await _context.Cards
            .Include(c => c.Card_Images)
            .Where(c => c.UserId == currentUserId)
            .ToListAsync();
        return View(userCards);
    }

    // 添加卡牌时自动关联当前用户
    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Create([Bind("Id,Name,Atk,Def,Desc,Level,Type,Attribute")] Card card)
    {
        if (ModelState.IsValid)
        {
            card.UserId = _userManager.GetUserId(User); // 绑定当前用户ID
            _context.Add(card);
            await _context.SaveChangesAsync();
            return RedirectToAction(nameof(Index));
        }
        return View(card);
    }
}

示例:确保用户只能修改自己的卡牌

在Edit/Delete等操作中,先验证资源是否属于当前用户:

public async Task<IActionResult> Edit(int? id)
{
    if (id == null) return NotFound();

    var currentUserId = _userManager.GetUserId(User);
    var card = await _context.Cards.FirstOrDefaultAsync(c => c.Id == id && c.UserId == currentUserId);
    
    if (card == null) return NotFound(); // 资源不属于当前用户时返回404

    return View(card);
}

第四步:添加授权保护

给所有需要登录才能访问的控制器或方法添加[Authorize]属性,确保只有登录用户才能操作:

[Authorize]
public class CardController : Controller
{
    // ... 控制器逻辑
}

[Authorize]
public class DeckController : Controller
{
    // ... 控制器逻辑
}

额外的最佳实践

  • 避免直接暴露用户ID:永远不要让前端传递用户ID来查询/修改数据,始终通过UserManager.GetUserId(User)获取当前用户ID,防止恶意用户篡改数据。
  • 数据验证:在服务层或控制器中,对所有修改/删除操作添加权限验证,确保用户只能操作自己的数据。
  • 更新数据库:修改模型后,执行EF Core迁移命令更新数据库:
    Add-Migration AddUserRelations
    Update-Database
    

这样一套下来,就能实现你想要的效果:新用户注册登录后,只能看到和管理自己的卡牌、卡组,不同用户的数据完全隔离。

内容的提问来源于stack exchange,提问作者dros

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:02:23