Session的使用

以.net演示

Posted by BY on September 30, 2023

session这个概念比较容易混淆,尤其是session机制常常会配合cookie一起使用,加上现在jwt用的比较多,session的概念比较模糊了,我对session的理解如下:

  1. ession是一种机制,用于解决http无状态的问题,但是http标准并没有定义session这个概念,http标准只提供了cookie,客户端也只有cookie、localstorage等存储方式,不存在session这样一个名词
  2. session的基本操作就是,服务端向客户端提供凭证或者直接发送数据,客户端每次请求带上凭证或者数据即可,如果提供的是凭证,即sessionId,服务端可以在内存中或者数据库中维护sessionId及相关信息的表,每次客户端发送信息来即可查看状态,一般sessionId放在cookie中,也可以放在localStorage中。也可以将所有信息,如用户名、密码等直接放在客户端,这样服务端就不需要再拿数据
  3. 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中间件所起的作用

  1. 生成唯一的sessionId,发往前端,id的有效期为20分钟
  2. 接受http请求时根据sessionId得到该sessionId所对应的一切信息,比如登录页用户输入的账号、密码
  3. session是.net core自带实现的状态机制,sessionId是.net core自动生成的,但是sessionKey和Value是自定义的,完全可以将token存在sessionKey中,如httpcontext.session.setstring("token", ''),这样就可以将session和token结合起来使用