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

Cookies

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

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)
{
} // 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}");
});
}
}
}

从HTTP 可以看到传送跟收到的Cookies 信息:

当存在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}");
});
}
}
}

HTTP Cookies 信息如下:

可以看到多出了.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容器中加入IHttpContextAccessorISessionWapper,如下:

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

老司机发车啦:https://github.com/SnailDev/SnailDev.NETCore2Learning

ASP.NET Core 2 学习笔记(十一)Cookies & Session的更多相关文章

  1. Asp.Net Core WebApi学习笔记(四)-- Middleware

    Asp.Net Core WebApi学习笔记(四)-- Middleware 本文记录了Asp.Net管道模型和Asp.Net Core的Middleware模型的对比,并在上一篇的基础上增加Mid ...

  2. ASP.NET Core 2 学习笔记(七)路由

    ASP.NET Core通过路由(Routing)设定,将定义的URL规则找到相对应行为:当使用者Request的URL满足特定规则条件时,则自动对应到相符合的行为处理.从ASP.NET就已经存在的架 ...

  3. ASP.NET Core 2 学习笔记(十三)Swagger

    Swagger也算是行之有年的API文件生成器,只要在API上使用C#的<summary />文件注解标签,就可以产生精美的线上文件,并且对RESTful API有良好的支持.不仅支持生成 ...

  4. ASP.NET Core 2 学习笔记(十二)REST-Like API

    Restful几乎已算是API设计的标准,通过HTTP Method区分新增(Create).查询(Read).修改(Update)和删除(Delete),简称CRUD四种数据存取方式,简约又直接的风 ...

  5. ASP.NET Core 2 学习笔记(十)视图

    ASP.NET Core MVC中的Views是负责网页显示,将数据一并渲染至UI包含HTML.CSS等.并能痛过Razor语法在*.cshtml中写渲染画面的程序逻辑.本篇将介绍ASP.NET Co ...

  6. sql server 关于表中只增标识问题 C# 实现自动化打开和关闭可执行文件(或 关闭停止与系统交互的可执行文件) ajaxfileupload插件上传图片功能,用MVC和aspx做后台各写了一个案例 将小写阿拉伯数字转换成大写的汉字, C# WinForm 中英文实现, 国际化实现的简单方法 ASP.NET Core 2 学习笔记(六)ASP.NET Core 2 学习笔记(三)

    sql server 关于表中只增标识问题   由于我们系统时间用的过长,数据量大,设计是采用自增ID 我们插入数据的时候把ID也写进去,我们可以采用 关闭和开启自增标识 没有关闭的时候 ,提示一下错 ...

  7. ASP.NET Core 2 学习笔记(一)开始

    原文:ASP.NET Core 2 学习笔记(一)开始 来势汹汹的.NET Core似乎要取代.NET Framework,ASP.NET也随之发布.NET Core版本.虽然名称沿用ASP.NET, ...

  8. ASP.NET Core MVC学习笔记

    最近由于疫情紧张,遂在家办公,在领导的带领下,学习了一下.Net Core MVC. 一,构建web应用 1.选择c#-所有平台-web  找到ASP.NET Core web应用程序 2.项目命名之 ...

  9. 使用Visual Studio Code开发Asp.Net Core WebApi学习笔记(十)-- 发布(Windows)

    本篇将在这个系列演示的例子上继续记录Asp.Net Core在Windows上发布的过程. Asp.Net Core在Windows上可以采用两种运行方式.一种是自托管运行,另一种是发布到IIS托管运 ...

随机推荐

  1. MySQL(增删改查补充)

    SQL语句数据行操作补充             create table tb12(                 id int auto_increment primary key,       ...

  2. Aizu 2249Road Construction 单源最短路变形《挑战程序设计竞赛》模板题

    King Mercer is the king of ACM kingdom. There are one capital and some cities in his kingdom. Amazin ...

  3. webpack快速入门——集中拷贝静态资源

    工作中会有一些已经存在但在项目中没有引用的图片资源或者其他静态资源(比如设计图.开发文档), 这些静态资源有可能是文档,也有可能是一些额外的图片.项目组长会要求你打包时保留这些静态资源, 直接打包到制 ...

  4. 六:MyBatis学习总结(六)——调用存储过程

    一.提出需求 查询得到男性或女性的数量, 如果传入的是0就女性否则是男性 二.准备数据库表和存储过程 create table p_user( id int primary key auto_incr ...

  5. 使用ie的filter来解决rgba在IE8下没有效果的问题

    使用ie的filter来解决rgba在IE8下没有效果的问题,css代码如下: background: rgba(255,255,255,0.1); filter:progid:DXImageTran ...

  6. CentOS7搭建FastDFS V5.11分布式文件系统-第二篇

    1.CentOS7 FastDFS搭建 前面已下载好了要用到的工具集,下面就可以开始安装了: 如果安装过程中出现问题,可以下载我提供的,当前测试可以通过的工具包: 点这里点这里 1.1 安装libfa ...

  7. SSH 转发学习【转】

    本地端口转发 假定有三台主机A.B.C.由于种种原因(无论是防火墙还是路由原因),AC两台主机之间无法连通.但是B却可以和A.C连通.这时候就可以用本地端口转发来实现A和C通过B来连通. A 192. ...

  8. apache URL重写 标志表 以及 错误解决方法

    Apache mod_rewrite规则重写的标志一览 1) R[=code](force redirect) 强制外部重定向 强制在替代字符串加上http://thishost[:thisport] ...

  9. 【树】Unique Binary Search Trees II

    题目: Given n, generate all structurally unique BST's (binary search trees) that store values 1...n. F ...

  10. Linux -- 使用笔记

    Linux新增分辨率1920x1080 sudo gedit /etc/default/grub 找到:#GRUB_GFXMODE=640x480 在这行下面加一行GRUB_GFXMODE=1920x ...