.netcore开发的Web应用共享Cookie的方法

本文介绍了如何在使用.NETCore开发的Web应用部署在多台服务器并通过Nginx负载均衡时,解决登录信息不共享的问题。通过使用共同的密钥文件对cookie进行加密解密,确保在服务器间登录状态的一致性。
摘要由CSDN通过智能技术生成

问题

使用.netcore开发的Web应用部署在多台服务器上,使用nginx使用负载均衡,可以提高WEB应用的可用率,但是简单的部署登录的信息不能在每台服务器之间共享,即在A服务器上登录后,下次访问可能被nginx指引到B服务器上访问,这时B服务器无法验证在A服务器的登录信息,会被重定向到登录页面,网上有很多文章写了相关问题的解决方案,但是都没写得很清楚的,综合几位大神的方法,重新记录一下。

解决方法

使用共同的密钥文件进行cookie的加解密,只需要指明密钥文件的路径,其他的代码没有变化

1、在Program.cs中添加以下代码:

builder.Services.AddAuthentication("cookie11")
               .AddCookie("cookie11", option =>
               {
                   option.Cookie.SameSite = SameSiteMode.Lax;
                   option.Cookie.HttpOnly = true;
                   option.LoginPath = new PathString("/Login");
                   option.AccessDeniedPath = new PathString("/RightErr");
               });

builder.Services.AddDataProtection()
                .SetApplicationName("cookieshare")
                .AddKeyManagementOptions(options =>
                {
                    options.XmlRepository = new XmlRepository();
                });

其中:SetApplicationName("cookieshare")是设置同一个应用的应用名称,XmlRepository是自己开发的一个类,这个类继承了IXmlRepository接口。

完整的Program.cs

using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.Extensions.Options;
using WebApplication12.Models;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllersWithViews();
builder.Services.AddAuthentication("cookie11")
               .AddCookie("cookie11", option =>
               {
                   option.Cookie.SameSite = SameSiteMode.Lax;
                   option.Cookie.HttpOnly = true;
                   option.LoginPath = new PathString("/Login");
                   option.AccessDeniedPath = new PathString("/RightErr");
               });

builder.Services.AddDataProtection()
                .SetApplicationName("cookieshare")
                .AddKeyManagementOptions(options =>
                {
                    options.XmlRepository = new XmlRepository();
                });

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();

app.UseRouting();

app.UseAuthentication();
app.UseAuthorization();

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

app.Run();

2、XmlRepository类代码:

using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.DataProtection.Repositories;
using System.Net;
using System.Security.Claims;
using System.Xml.Linq;

namespace WebApplication12.Models
{
    public class XmlRepository : IXmlRepository
    {
        private readonly string _KeyContentPath = "";

        public XmlRepository()
        {
            _KeyContentPath = Path.Combine(Directory.GetCurrentDirectory(), "key.xml");
        }

        public IReadOnlyCollection<XElement> GetAllElements()
        {
            var elements = new List<XElement>() { XElement.Load(_KeyContentPath) };
            return elements;
        }

        public void StoreElement(XElement element, string friendlyName)
        {

        }
    }
}

其中的key.xml文件需要放在Web应用下,指明文件路径。

3、登录方法

public IActionResult Login()
{
    var claims = new List<Claim>
                {
                   new Claim(ClaimTypes.Name, "mm")
                };
    var claimsIdentity = new ClaimsIdentity(claims, "cookie11");
    AuthenticationProperties ap = new AuthenticationProperties
    {
        ExpiresUtc = DateTime.UtcNow.AddMinutes(20)
    };
    HttpContext.SignInAsync("cookie11", new ClaimsPrincipal(claimsIdentity), ap);
    return RedirectToAction("Index", "Home");
}

4、生成key.xml文件

我创建了一个NUnit测试项目,需要引用Microsoft.AspNetCore.DataProtection和Microsoft.Extensions.DependencyInjection包

[Test]
public void Test1()
{


    var directory = "d:\\temp\\a\\";
    var services = new ServiceCollection();
    services
        .AddDataProtection()
        .PersistKeysToFileSystem(new DirectoryInfo(directory));
    var keyManager = services
        .BuildServiceProvider()
        .GetRequiredService<IKeyManager>();

    keyManager.CreateNewKey(
        DateTimeOffset.Now, DateTimeOffset.Now.AddYears(100));
   

    
    Assert.Pass();
}

运行后会在d:\temp\a下创建一个随机名称的xml文件,将这个xml文件重命名为key.xml,添加到Web应用中,并将复制到输出目录设置为“如果较新则复制”

<?xml version="1.0" encoding="utf-8"?>
<key id="32703ef5-aebc-4261-afba-9dfec69c135c" version="1">
  <creationDate>2024-01-07T08:44:17.8516684Z</creationDate>
  <activationDate>2024-01-07T16:44:17.8505563+08:00</activationDate>
  <expirationDate>2124-01-07T16:44:17.8515013+08:00</expirationDate>
  <descriptor deserializerType="Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60">
    <descriptor>
      <encryption algorithm="AES_256_CBC" />
      <validation algorithm="HMACSHA256" />
      <masterKey p4:requiresEncryption="true" xmlns:p4="http://schemas.asp.net/2015/03/dataProtection">
        <!-- Warning: the key below is in an unencrypted form. -->
        <value>OhW8u4UznUy//I2hPbkzVhJE5oloPSRnzZ+lfSNk+t6MsHEdDm6wGaNVVg81BwKqosETBP6KTKDKEmOOWElK0w==</value>
      </masterKey>
    </descriptor>
  </descriptor>
</key>

小结

这样部署到多台服务器上,登录的Cookie就能统一验证了。

参考文档

ASP.NET Core 2.0 多应用实现Cookie共享

《ASP.NET Core 6框架揭秘》实例演示[20]:“数据保护”框架基于文件的密钥存储...

  • 9
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值