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

Fab*_*uez 4 c# state asp.net-core-mvc asp.net-core-webapi asp.net-core-1.1

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

例如,用户可能想查看由其房地产经纪人中的任何人检查的所有财产的列表。在这种情况下,他单击Web /电话应用程序中的某个位置,然后该应用程序向HTTP发送HTTP GET请求以检索属性列表。Web API在接收到此请求后,首先检查哪个用户正在请求此请求,然后检查该用户所属的代理,然后返回属于该代理的所有属性。所以...这些是我拥有的[简化]模型:

[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; }
}
Run Code Online (Sandbox Code Playgroud)

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));
}
Run Code Online (Sandbox Code Playgroud)

现在,对A​​PI的所有GET请求都是这样过滤的-API返回与已登录用户代理有关的记录。无论用户请求检查清单,房东还是租户,API始终仅返回属于用户代理机构的记录。

现在我知道ASP .Net Core是无状态的,因此,当用户登录时,我无法将用户对象保存在服务器上,并且无法将其存储在内存中,可以在每个控制器操作中调用它。但是我觉得每次API收到任何GET请求以查找此用户所属的代理机构时,这种往返数据库的操作都是浪费的。有一个更好的方法吗?总的来说,我对ASP和Web开发还很陌生。任何想法/提示/指针将不胜感激。

Ron*_*n C 5

现在我知道ASP .Net Core是无状态的,因此,当用户登录时,我无法将用户对象保存在服务器上,并且无法将其存储在内存中,可以在每个控制器操作中调用它。但是我觉得每次API收到任何GET请求以查找此用户所属的代理机构时,这种往返数据库的操作都是浪费的。


欢迎使用网络,这是一个无状态的环境。如果您需要用户记录来处理每个http请求,则基本上可以有以下几种选择:

  1. 根据需要从数据库获取它
  2. 将需要的部分记录放入会话中
  3. 将您需要的部分记录放入Cookie

每种方法都有优点和缺点。

选项1会为您提供来自用户记录的绝对最新信息,但要付出额外的数据库往返费用,以应付任何请求。而且,如果您有多个不同的记录来处理请求,那么您可能会因每个请求的构造方式而导致数据库多次往返,

如果您将Asp.Net Core应用程序配置为使用内存中的会话提供程序,则选项2可以消除数据库往返的任何请求。但是缺点是,如果Web应用程序被回收(如果在IIS后面运行,这是很常见的),则会话将被清除。如果您已将会话配置为使用SqlServer之类的数据库提供程序,则仍将为每个请求从数据库读取会话中的每个请求进行数据库往返(但这仅是一次往返,而不是几次往返,具体取决于您所拥有的放置在会话中以及编译信息所需的数据库往返次数。)将信息放置在数据库支持的会话中的不利之处在于,即使请求不需要任何信息,它也会强制每个请求进行数据库往返放置在会话中。而且,如果您不小心,会话中存储的数据大小(每个请求都从数据库中查询)的大小很快就会变大。有时“仅将其放入会话”可能太容易了,这最终会导致性能问题。

选项3将所需的数据放在cookie中,该cookie将与每个请求一起在http请求的标头中传播。这样做的缺点是,它会使每个文件请求略大(甚至甚至是图像请求),您可能希望将cookie限制为仅https请求,以防止信息通过Internet清晰地传输。这种方法通常仅用于非常少量的数据。

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

您可以在此处阅读有关Asp.Net Core会话和应用状态的更多信息:https : //docs.microsoft.com/zh-cn/aspnet/core/fundamentals/app-state