谈谈ASP.NET CORE 的会话和应用状态

前言

有这样普遍的应用场景:我们需要保存用户的登录状态,以此来对其进行访问的授权。我们知道,HTTP 是无状态的协议。 不采取其他步骤的情况下,HTTP 请求是不保留用户值或应用状态的独立消息。 本文介绍了几种保留请求间用户数据和应用状态的方法。

状态管理

存储方法

存储机制

Cookie

HTTP Cookie(可能包括使用服务器端应用代码存储的数据)

Session state

HTTP Cookie 和服务器端应用代码

TempData

HTTP Cookie 或会话状态

Query strings

HTTP 查询字符串

Hidden fields

HTTP 窗体字段

HttpContext.Items

服务器端应用代码

缓存

服务器端应用代码

依赖关系注入

服务器端应用代码

Cookie 存储所有请求的数据。 因为 Cookie 是随每个请求发送的,所以它们的大小应该保持在最低限度。 理想情况下,仅标识符应存储在 Cookie 中,而数据则由应用存储。 大多数浏览器 Cookie 大小限制为 4096 个字节。 每个域仅有有限数量的 Cookie 可用。

由于 Cookie 易被篡改,因此它们必须由服务器进行验证。 客户端上的 Cookie 可能被用户删除或者过期。 但是,Cookie 通常是客户端上最持久的数据暂留形式。

Cookie 通常用于个性化设置,其中的内容是为已知用户定制的。 大多数情况下,仅标识用户,但不对其进行身份验证。 Cookie 可以存储用户名、帐户名或唯一的用户 ID(例如 GUID)。 然后,可以使用 Cookie 访问用户的个性化设置,例如首选的网站背景色。

发布 Cookie 和处理隐私问题时,请留意欧盟一般数据保护条例 (GDPR)。 有关详细信息,请参阅 ASP.NET Core 中的一般数据保护条例 (GDPR) 支持

Session state

会话状态是用户浏览 Web 应用时 ASP.NET Core 存储用户数据的方案。会话状态使用应用维护的存储来保存客户端所有请求的数据。会话数据由缓存支持并被视为临时数据 —— 站点应在没有会话数据的情况下继续运行。

ASP.NET Core 通过向客户端提供包含会话 ID 的 Cookie 来维护会话状态,该会话 ID 与每个请求一起发送到应用。应用使用会话 ID 来获取会话数据。

会话状态具有以下行为:

  • 由于会话 Cookie 是特定于浏览器的,因此不能跨浏览器共享会话。
  • 浏览器会话结束时删除会话 Cookie。
  • 如果收到过期的会话 Cookie,则创建使用相同会话 Cookie 的新会话。
  • 不会保留空会话 - 会话中必须设置了至少一个值以保存所有请求的会话。 会话未保留时,为每个新的请求生成新会话 ID。
  • 应用在上次请求后保留会话的时间有限。 应用设置会话超时,或者使用 20 分钟的默认值。 会话状态适用于存储特定于特定会话的用户数据,但该数据无需永久的会话存储。
  • 调用 ISession.Clear 实现或者会话过期时,会删除会话数据。
  • 没有默认机制告知客户端浏览器已关闭或者客户端上的会话 Cookie 被删除或过期的应用代码。
  • ASP.NET Core MVC 和 Razor Pages 模板包括对一般数据保护条例 (GDPR) 的支持。 默认情况下,会话状态 cookie 不标记为“基本”,因此,除非站点访问者允许跟踪,否则会话状态不起作用。 有关详细信息,请参阅 在 ASP.NET Core中的常规数据保护法规 (GDPR) 支持

 警告

请勿将敏感数据存储在会话状态中。 用户可能不会关闭浏览器并清除会话 Cookie。 某些浏览器会保留所有浏览器窗口中的有效会话 Cookie。 会话可能不限于单个用户 - 下一个用户可能继续使用同一会话 Cookie 浏览应用。

内存中缓存提供程序在应用驻留的服务器内存中存储会话数据。 在服务器场方案中:

配置 Session state

在 ASP.NET Core 中启用 Session state,Startup 必须包含:

  • 对 ConfigureServices 中 AddSession 的调用

具体的配置代码如下:

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddDistributedMemoryCache();

        services.AddSession(options =>
        {
            // Set a short timeout for easy testing.
            options.IdleTimeout = TimeSpan.FromSeconds(10);
            options.Cookie.HttpOnly = true;
            // Make the session cookie essential
            options.Cookie.IsEssential = true;
        });

        services.AddMvc()
            .SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseExceptionHandler("/Error");
            app.UseHsts();
        }

        app.UseHttpsRedirection();
        app.UseStaticFiles();
        app.UseSession();
        app.UseHttpContextItemsMiddleware();
        app.UseMvc();
    }
}

注:中间件的顺序很重要。 在前面的示例中,在 UseMvc 之后调用 UseSession 时会发生 InvalidOperationException 异常。 有关详细信息,请参阅中间件排序。配置好 Session state 后,HttpContext.Session 就可以使用了。。

官方教程还有更多关于 Session state 的配置、设置和获取的相关内容,此处不再赘述

TempData

TempData 在 ASP.NET Core 2.0 或更高版本中,默认基于 Cookie 实现。通过配置也可以基于 Session state 实现 TempData:

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<CookiePolicyOptions>(options =>
    {
        options.CheckConsentNeeded = context => true;
        options.MinimumSameSitePolicy = SameSiteMode.None;
    });

    services.AddMvc()
        .SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
        .AddSessionStateTempDataProvider();

    services.AddSession();
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        app.UseDatabaseErrorPage();
    }
    else
    {
        app.UseExceptionHandler("/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();
    app.UseStaticFiles();
    app.UseCookiePolicy();
    app.UseSession();
    app.UseMvc();
}

HttpContext.Items

处理单个请求时,使用 HttpContext.Items 集合存储数据。处理请求后,放弃集合的内容。通常使用 Items 集合允许组件或中间件在请求期间在不同时间点操作且没有直接传递参数的方法时进行通信。

示例:中间件将 isVerified 添加到 Items 集合。

app.Use(async (context, next) =>
{
    // perform some verification
    context.Items["isVerified"] = true;
    await next.Invoke();
});

然后,在管道中,另一个中间件可以使用 isVerified 值

app.Run(async (context) =>
{
    await context.Response.WriteAsync($"Verified: {context.Items["isVerified"]}");
});

对于只供单个应用使用的中间件,string 键是可以接受的。 应用实例间共享的中间件应使用唯一的对象键以避免键冲突。 以下示例演示如何使用中间件类中定义的唯一对象键:

public class HttpContextItemsMiddleware
{
    private readonly RequestDelegate _next;
    public static readonly object HttpContextItemsMiddlewareKey = new Object();

    public HttpContextItemsMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task Invoke(HttpContext httpContext)
    {
        httpContext.Items[HttpContextItemsMiddlewareKey] = "K-9";

        await _next(httpContext);
    }
}

public static class HttpContextItemsMiddlewareExtensions
{
    public static IApplicationBuilder 
        UseHttpContextItemsMiddleware(this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<HttpContextItemsMiddleware>();
    }
}

其他代码可以使用通过中间件类公开的键访问存储在 HttpContext.Items 中的值:

HttpContext.Items
    .TryGetValue(HttpContextItemsMiddleware.HttpContextItemsMiddlewareKey, 
        out var middlewareSetValue);
SessionInfo_MiddlewareValue = 
    middlewareSetValue?.ToString() ?? "Middleware value not set!";

缓存

缓存是存储和检索数据的有效方法。 应用可以控制缓存项的生存期。

缓存数据未与特定请求、用户或会话相关联。 请注意不要缓存可能由其他用户请求检索的特定于用户的数据。更多缓存知识可以看我的这篇文章:https://blog.csdn.net/weixin_41372626/article/details/104634729

依赖关系注入

使用依赖关系注入可向所有用户提供数据

1.定义一项包含数据的服务。 例如,定义一个名为 MyAppData 的类:

public class MyAppData
{
    // Declare properties and methods
}

2.将服务类添加到 Startup.ConfigureServices

public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton<MyAppData>();
}

3.使用数据服务类:

public class IndexModel : PageModel
{
    public IndexModel(MyAppData myService)
    {
        // Do something with the service
        //    Examples: Read data, store in a field or property
    }
}

参考文献:https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/app-state?view=aspnetcore-2.1#tempdat

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值