在 ASP .Net Core Web API 中保持登录用户的状态

Keeping state of logged in user in ASP .Net Core Web API

我有一个 ASP .Net Core 1.1 Web Api,它处理来自前端 Web 应用程序和 phone 应用程序的请求。该应用程序供房地产经纪人对房产进行检查。因此,该系统具有检查、财产、用户、代理等实体。用户(即房地产经纪人)和财产属于代理。所以一个地产代理可以有一个或多个用户和一个或多个属性。

例如,用户可能想要查看其房地产代理中任何人检查过的所有房产的列表。在这种情况下,他单击 web/phone 应用程序中的某处,该应用程序向 API 发送 HTTP GET 请求以检索属性列表。 WebAPI收到这个请求后,首先检查哪个用户在请求这个,然后检查这个用户属于哪个机构,然后returns属于这个机构的所有属性。所以...这些是我拥有的 [简化] 模型:

[Table("agency")]
public class Agency
{

    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    [Column("agency_id")]
    public int? Id { get; set; }

    [Column("name")]
    public string Name { get; set; }
}

[Table("user")]
public class User
{

    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    [Column("user_id")]
    public int? Id { get; set; }

    [Column("username")]
    public string Username { get; set; }

    [Column("agency_id")]
    public int AgencyId { get; set; }

    [ForeignKey("AgencyId")]
    public Agency Agency { get; set; }
}

[Table("property")]
public class Property
{

    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    [Column("property_id")]
    public int? Id { get; set; }

    [Column("address")]
    public string Address { get; set; }

    [Column("agency_id")]
    public int AgencyId { get; set; }

    [ForeignKey("AgencyId")]
    public Agency Agency { get; set; }
}

Web 上处理上述请求的控制器操作 API 如下所示:

[Authorize]
[HttpGet]
public async Task<IActionResult> GetProperties()
{
    // Get Auth0 identifier for the user performing the request
    string nameIdentifier = User.Claims.FirstOrDefault(c => c.Type == System.Security.Claims.ClaimTypes.NameIdentifier)?.Value;
    // Retrieve this user from the database
    User user = await _context.User.SingleOrDefaultAsync(u => u.Username == nameIdentifier);
    // Return a list of properties that belong to the user's agency
    return Ok(_context.Properties
        .Where(p.AgencyId == user.AgencyId));
}

现在,对 API 的所有 GET 请求都像这样过滤 - 其中 API returns 记录属于已登录用户的代理机构。无论用户要求的是验房名单,还是房东,还是租户,API总是returns只记录属于用户的代理机构。

现在我知道ASP.Net Core 是无状态的,所以我无法在用户登录时将用户对象保存在服务器上,并在内存中准备好在每个控制器操作中调用.但我觉得每次 API 收到任何 GET 请求以查明该用户属于哪个机构时,这种往返数据库的方式都是浪费。有一个更好的方法吗?我对 ASP 和一般的 Web 开发还很陌生。任何 ideas/hints/pointers 将不胜感激。

Now I know ASP .Net Core is stateless, so I can't save the user object on the server when the user logs in, and have it in memory ready to be called in each controller action. But I feel like this round trip to the database EVERY time the API receives any GET request to find out which agency this user belongs to is wasteful.


欢迎使用网络,它是一个无状态的环境。如果您需要用户记录来处理每个 http 请求,您基本上有几个选择:
  1. 根据请求从数据库中获取它
  2. 将您需要的记录部分放入session
  3. 将您需要的记录部分放入cookie

每种方法都有利有弊。

选项 1 将为您提供来自用户记录的绝对最新信息,但代价是每次请求都要进行一次额外的数据库往返。如果你有多个不同的记录,你需要处理请求,你可能最终会为每个请求进行多次数据库往返,这取决于你如何构建事物,

如果您将 Asp.Net 核心应用程序配置为使用 In-Memory Session 提供程序,则选项 2 可以消除所有请求的数据库往返。但缺点是,如果 Web 应用程序被回收(如果 运行 在 IIS 后面,这很常见),那么 session 将被清除。如果您将 session 配置为使用像 SqlServer 这样的数据库提供程序,那么您仍然会为每个请求进行一次数据库往返,因为它从数据库中读取 session (但这只是一次往返可能有几个,具体取决于您在 session 中放置的内容以及编译信息所需的数据库往返次数。)将信息放置在支持 session 的数据库中的一个缺点是它会强制进行数据库往返对于每个请求,即使请求不需要放置在 session 中的任何信息。而且,如果您不小心,存储在 session 中的数据大小(以及每个请求从数据库中查询的数据)会很快变得非常大。有时“将它扔进 session”太容易了,这最终会导致性能问题。

选项 3 将所需数据放入 cookie 中,该 cookie 将随 http 请求 header 中的每个请求一起传送。这样做的缺点是它使每个文件请求略微变大(通常甚至是图像请求),您可能希望将 cookie 限制为仅 https 请求以防止信息在互联网上以明文方式传输。这种方法通常只用于非常少量的数据。

此摘要绝不是详尽无遗的,还有其他方法可以跟踪状态(查询参数等)以及所选任何方法的其他安全注意事项。主要的收获是,是的,网络是一个无状态的环境,但是仍然有一些方法可以跟踪状态,但是所有这些方法都有利有弊,没有一种方法总是最好的。大多数大型 Web 应用程序针对其 Web 应用程序的不同方面使用所有可用方法的变体。

您可以在此处阅读有关 Asp.NET 核心 session 和应用程序状态的更多信息:https://docs.microsoft.com/en-us/aspnet/core/fundamentals/app-state