session这个概念比较容易混淆,尤其是session机制常常会配合cookie一起使用,加上现在jwt用的比较多,session的概念比较模糊了,我对session的理解如下:
- ession是一种机制,用于解决http无状态的问题,但是http标准并没有定义session这个概念,http标准只提供了cookie,客户端也只有cookie、localstorage等存储方式,不存在session这样一个名词
- session的基本操作就是,服务端向客户端提供凭证或者直接发送数据,客户端每次请求带上凭证或者数据即可,如果提供的是凭证,即sessionId,服务端可以在内存中或者数据库中维护sessionId及相关信息的表,每次客户端发送信息来即可查看状态,一般sessionId放在cookie中,也可以放在localStorage中。也可以将所有信息,如用户名、密码等直接放在客户端,这样服务端就不需要再拿数据
- token即凭证,可以看做sessionId的一种实现,jwt即json web token,是生成token的一种算法
鉴于koa并没有原生提供session的支持,这里使用.net core来演示一下session的使用,以下来源于微软文档以及网上找到的博客。
.net core在创建web api项目时会默认把https选项给勾选上,可以取消勾选。
前后台代码如下
vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
server: {
proxy: {
"/api": {
target: "http://localhost:28698",
// target: 'http://localhost:3000/',
// changeOrigin: true,
secure: false,
rewrite: (path) => path.replace(/^\/api/, ""),
},
},
},
})
.net core startup.cs
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.OpenApi.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace WebApplication3
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "WebApplication3", Version = "v1" });
});
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddMvc().AddSessionStateTempDataProvider();
services.AddSession();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "WebApplication3 v1"));
}
app.UseSession();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}
.net core WeatherForecastController.cs
提供两个方法模拟登录和登录之后获取数据
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace WebApplication3.Controllers
{
[ApiController]
[Route("")]
public class WeatherForecastController : ControllerBase
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
private readonly ILogger<WeatherForecastController> _logger;
public WeatherForecastController(ILogger<WeatherForecastController> logger)
{
_logger = logger;
}
[HttpPost]
public IEnumerable<WeatherForecast> Login()
{
HttpContext.Session.SetString("Test", "123");
return Enumerable.Empty<WeatherForecast>();
}
[HttpGet]
public IEnumerable<WeatherForecast> Get()
{
if(HttpContext.Session.GetString("Test") == "123")
{
var rng = new Random();
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
})
.ToArray();
}else
{
return Enumerable.Empty<WeatherForecast>();
}
}
}
}
可以看到,当点击登录按钮之后,.net core生成了唯一的sessionid,发到了前端并设置成cookie
当登录完成之后,再次请求数据就可以拿到数据了,此时,若清除浏览器中的cookie,则获取不到数据,或者换个浏览器也可以看到同样的效果
以上的例子还不足以支持一个登录服务,但是大概可以猜测.net core中session中间件所起的作用
- 生成唯一的sessionId,发往前端,id的有效期为20分钟
- 接受http请求时根据sessionId得到该sessionId所对应的一切信息,比如登录页用户输入的账号、密码
- session是.net core自带实现的状态机制,sessionId是.net core自动生成的,但是sessionKey和Value是自定义的,完全可以将token存在sessionKey中,如httpcontext.session.setstring("token", ''),这样就可以将session和token结合起来使用