想象一个应用程序,用户可以在其中管理某种项目(他的任务、他的书籍收藏或其他什么)。用户只能访问自己的项目,而不能访问其他用户的项目。我如何确保在我的 HotChocolate GraphQl 后端中做到这一点?我是否总是必须记住编写仅限于用户 ID 的查询,或者是否有更好的方法?我担心有人可能会忘记将查询限制为用户 ID,然后泄露其他用户的数据。
[Authorize]
public class Items
{
public int Id { get; set; } // id of the item
public int UserId { get; set; } // id of the user who owns the item
public string Title { get; set; } = null!; // title of the item, e.g. title of a book
}
[QueryType]
public class ItemQueries
{
public IQueryable<Contract> GetItems(ApplicationDbContext context, [UserId] int userId)
{
// I think it's error prone (e.g. one could easily forget about it)
// that I always have to remember to query by the user id.
// Is there a better solution to that?
return context.Items.Where(item => item.UserId == userId);
}
}
虽然直接按用户 ID 过滤查询以确保用户仅在 GraphQL API 中访问自己的数据是一种简单的方法,但可能值得探索其他选项,例如:
自动过滤中间件 您可以创建一个自定义 GraphQL 中间件,自动将特定于用户的过滤应用于所有查询。该中间件可以检查传入的 GraphQL 查询,并根据操作类型和正在访问的实体,附加必要的Where子句以确保根据当前用户的ID过滤数据。
自定义属性和反射 另一种方法是创建自定义属性,例如 [UserScoped],您可以将其应用于代表用户所有权的模型属性。然后,在基本查询类或中间件中使用反射,自动将用户 ID 过滤器注入到标有此属性的模型的查询中。
在 Entity Framework Core 中利用全局查询过滤器 如果您使用 Entity Framework Core,则可以利用全局查询过滤器自动将过滤器应用于您的查询。例如,您可以在 Items DbSet 上定义一个全局过滤器,以仅包含 UserId 与当前用户 ID 匹配的项目。这种方法集中了您的访问控制逻辑,降低了意外暴露用户数据的风险。
希望这有帮助!