美文网首页
ASP.NET Core 2 学习笔记(十一)Cookies &

ASP.NET Core 2 学习笔记(十一)Cookies &

作者: 懒懒的程序员一枚 | 来源:发表于2019-05-28 23:17 被阅读0次

    基本上HTTP是没有记录状态的协定,但可以通过Cookies将Request来源区分出来,并将部分数据暂存于Cookies及Session,是写网站常用的用户数据暂存方式。
    本篇将介绍如何在ASP.NET Core使用Cookie及Session。

    Cookies

    Cookies是将用户数据存在Client的浏览器,每次Request都会把Cookies送到Server。
    在ASP.NET Core中要使用Cookie,可以通过HttpContext.Request及HttpContext.Response存取:

    Startup.cs

     System.Threading.Tasks;
    
    using Microsoft.AspNetCore.Builder;
    
    using Microsoft.AspNetCore.Hosting;
    
    using Microsoft.AspNetCore.Http;
    
    using Microsoft.Extensions.DependencyInjection;
    
     
    
    namespace MyWebsite
    
    {
    
        public class Startup
    
        {
    
            // This method gets called by the runtime. Use this method to add services to the container.
    
            // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
    
            public void ConfigureServices(IServiceCollection services)
    
            {
    
            }
    
     
    
            // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    
            public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    
            {
    
                if (env.IsDevelopment())
    
                {
    
                    app.UseDeveloperExceptionPage();
    
                }
    
     
    
                // app.Run(async (context) =>
    
                // {
    
                //     await context.Response.WriteAsync("Hello World!");
    
                // });
    
     
    
                app.Run(async (context) =>
    
                {
    
                    string message;
    
     
    
                    if (!context.Request.Cookies.TryGetValue("Sample", out message))
    
                    {
    
                        message = "Save data to cookies.";
    
                    }
    
                    context.Response.Cookies.Append("Sample", "This is Cookies.");
    
                    // 刪除 Cookies 数据
    
                    //context.Response.Cookies.Delete("Sample");
    
     
    
                    await context.Response.WriteAsync($"{message}");
    
                });
    
            }
    
        }
    
    }
    
    1215970-20180605105336998-266020879.png

    当存在Cookies 的信息越多,封包就会越大,因为每个Request 都会带着Cookies 数据。

    Session

    Session是通过Cookies内的唯一识别信息,把用户数据存在Server端内存、NoSQL或数据库等。
    要在ASP.NET Core使用Session需要先加入两个服务:
    •Session容器
    Session可以存在不同的地方,透过DI IDistributedCache物件,让Session服务知道要将Session存在哪边。
    (之后的文章会介绍到IDistributedCache分散式快取)
    •Session服务
    在DI容器加入Session服务。并将Session的Middleware加入Pipeline。

    Startup.cs

    
    using System;
    
    using System.Collections.Generic;
    
    using System.Linq;
    
    using System.Threading.Tasks;
    
    using Microsoft.AspNetCore.Builder;
    
    using Microsoft.AspNetCore.Hosting;
    
    using Microsoft.AspNetCore.Http;
    
    using Microsoft.Extensions.DependencyInjection;
    
     
    
    namespace MyWebsite
    
    {
    
        public class Startup
    
        {
    
            // This method gets called by the runtime. Use this method to add services to the container.
    
            // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
    
            public void ConfigureServices(IServiceCollection services)
    
            {
    
                // 将 Session 存在 ASP.NET Core 内存中
    
                services.AddDistributedMemoryCache();
    
                services.AddSession();
    
            }
    
     
    
            // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    
            public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    
            {
    
                if (env.IsDevelopment())
    
                {
    
                    app.UseDeveloperExceptionPage();
    
                }
    
     
    
                // SessionMiddleware 加入 Pipeline
    
                app.UseSession();
    
     
    
                app.Run(async (context) =>
    
                {
    
                    context.Session.SetString("Sample", "This is Session.");
    
                    string message = context.Session.GetString("Sample");
    
                    await context.Response.WriteAsync($"{message}");
    
                });
    
            }
    
        }
    
    }
    
    1215970-20180605105853413-1164247187.png

    可以看到多出了.AspNetCore.Session,.AspNetCore.Session就是Session的唯一识别信息。
    每次Request时都会带上这个值,当Session服务取得这个值后,就会去Session容器找出专属这个值的Session数据。

    对象类型

    以前ASP.NET可以将对象直接存放到Session,现在ASP.NET Core Session不再自动序列化对象到Sesson。
    如果要存放对象到Session就要自己序列化了,这边以JSON格式作为范例:

    Extensions\SessionExtensions.cs

    
    using Microsoft.AspNetCore.Http;
    
    using Newtonsoft.Json;
    
     
    
    namespace MyWebsite.Extensions
    
    {
    
        public static class SessionExtensions
    
        {
    
            public static void SetObject<T>(this ISession session, string key, T value)
    
            {
    
                session.SetString(key, JsonConvert.SerializeObject(value));
    
            }
    
     
    
            public static T GetObject<T>(this ISession session, string key)
    
            {
    
                var value = session.GetString(key);
    
                return value == null ? default(T) : JsonConvert.DeserializeObject<T>(value);
    
            }
    
        }
    
    }
    

    通过上面扩展方法,就可以将对象存取至Session,如下:

    
    using MyWebsite.Extensions;
    
    using MyWebsite.Models;
    
    // ...
    
    var user = context.Session.GetObject<UserModel>("user");
    
    context.Session.SetObject("user", user);
    

    安全性

    虽然Session数据都存在Server端看似安全,但如果封包被拦截,只要拿到.AspNetCore.Session就可以取到该用户数据,也是有风险。
    有些安全调整建议实作:
    •SecurePolicy
    限制只有在HTTPS连线的情况下,才允许使用Session。如此一来变成加密连线,就不容易被拦截。
    •IdleTimeout
    修改合理的Session到期时间。预设是20分钟没有跟Server互动的Request,就会将Session变成过期状态。
    (20分钟有点长,不过还是要看产品需求。)
    •Name
    没必要将Server或网站技术的信息爆露在外面,所以预设Session名称.AspNetCore.Session可以改掉。

    
    // ...
    
    public void ConfigureServices(IServiceCollection services)
    
    {
    
        services.AddDistributedMemoryCache();
    
        services.AddSession(options =>
    
        {
    
            options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
    
            options.Cookie.Name = "mywebsite";
    
            options.IdleTimeout = TimeSpan.FromMinutes(5);
    
        });
    
    }
    

    强类型

    由于Cookies及Session预设都是使用字串的方式存取资料,弱类型无法在开发阶段判断有没有打错字,还是建议包装成强类型比较好。
    而且直接存取Cookies/Session的话逻辑相依性太强,对单元测试很不友善,所以还是建议包装一下。

    Wappers\SessionWapper.cs

    
    using Microsoft.AspNetCore.Http;
    
    using MyWebsite.Extensions;
    
    using MyWebsite.Models;
    
    // ...
    
    namespace MyWebsite.Wappers
    
    {
    
        public interface ISessionWapper
    
        {
    
            UserModel User { get; set; }
    
        }
    
     
    
        public class SessionWapper : ISessionWapper
    
        {
    
            private static readonly string _userKey = "session.user";
    
            private readonly IHttpContextAccessor _httpContextAccessor;
    
     
    
            public SessionWapper(IHttpContextAccessor httpContextAccessor)
    
            {
    
                _httpContextAccessor = httpContextAccessor;
    
            }
    
     
    
            private ISession Session
    
            {
    
                get
    
                {
    
                    return _httpContextAccessor.HttpContext.Session;
    
                }
    
            }
    
     
    
            public UserModel User
    
            {
    
                get
    
                {
    
                    return Session.GetObject<UserModel>(_userKey);
    
                }
    
                set
    
                {
    
                    Session.SetObject(_userKey, value);
    
                }
    
            }
    
        }
    
    }
    

    在DI容器中加入IHttpContextAccessor及ISessionWapper,如下:

    Startup.cs

    
    // ...
    
    public void ConfigureServices(IServiceCollection services)
    
    {
    
        services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
    
        services.AddSingleton<ISessionWapper, SessionWapper>();
    
    }
    

    IHttpContextAccessor
    ASP.NET Core实现了IHttpContextAccessor,让HttpContext可以轻松的注入给需要用到的对象使用。
    由于IHttpContextAccessor只是取用HttpContext实例的接口,用Singleton的方式就可以供其它物件使用。

    在Controller就可以直接注入ISessionWapper,以强类型的方式存取Session,如下:

    Controllers/HomeController.cs

    using Microsoft.AspNetCore.Mvc;
    
    using MyWebsite.Wappers;
    
     
    
    namespace MyWebsite.Controllers
    
    {
    
        public class HomeController : Controller
    
        {
    
            private readonly ISessionWapper _sessionWapper;
    
     
    
            public HomeController(ISessionWapper sessionWapper)
    
            {
    
                _sessionWapper = sessionWapper;
    
            }
    
     
    
            public IActionResult Index()
    
            {
    
                var user = _sessionWapper.User;
    
                if (user == null) user = new Models.UserModel();
    
                _sessionWapper.User = user;
    
                return Ok(user);
    
            }
    
        }
    
    }
    

    参考

    Introduction to session and application state in ASP.NET Core

    相关文章

      网友评论

          本文标题:ASP.NET Core 2 学习笔记(十一)Cookies &

          本文链接:https://www.haomeiwen.com/subject/trrstctx.html