C# 如何在项目之间共享 authentication/authorization cookie?

C# How to share authentication/authorization cookie between projects?

这是一个与概念方法有关的问题。

所以我有两个项目 - 其中一个已经实施了身份验证并且工作正常。这是一个带有 OpenID + Cookie 的 .net 核心 SPA(没有 ASP.NET Core Identity)。

第二个项目是 REST API,我想使用该 cookie 来授权一些端点,所以基本上是 SSO。

对我来说最大的挑战是我不知道应该如何修改第二个项目以“接受”第一个项目的 cookie - 我至少需要一些起点。

这个根本没有帮助:https://docs.microsoft.com/en-us/aspnet/core/security/cookie-sharing?view=aspnetcore-6.0 从文档中不清楚我需要在两个项目中做什么才能使其工作。

所以我想的是将 services.AddAuthentication(...) 从第一个项目复制粘贴到第二个项目,这样他们就可以共享相同的 Authority - 我相信第二个项目没有其他方法知道 cookie 是“我们的”cookie 吗?

更新: 我在这里提供代码示例 - 通过下面的设置,它不断尝试将我重定向到登录,因为不认为它已通过身份验证:

项目 A(用户登录,我们希望为此项目和其他项目“生成”cookie):

public void ConfigureServices(IServiceCollection services)
{
    
    services.AddAuthentication(options => {
            options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
        })
        .AddCookie(options => {
            options.Cookie.Name = "test";
            options.Cookie.Domain = ".localhost";
            options.Cookie.Path = "/";
        })
        .AddOpenIdConnect(options =>
        {
            options.ClientId = "xxx";
            options.ClientSecret = "xxx";
            options.MetadataAddress = $"https://login.microsoftonline.com/xxx/v2.0/.well-known/openid-configuration?appid=xxx";
            options.Authority = $"https://login.microsoftonline.com/xxx/oauth2/v2.0";
            options.ResponseType = "code";
            options.GetClaimsFromUserInfoEndpoint = true;
            options.TokenValidationParameters = new TokenValidationParameters {
                NameClaimType = "name"
            };
        });

    services.AddDataProtection()
        .PersistKeysToFileSystem(new System.IO.DirectoryInfo("/cookies"))
        .SetApplicationName("SharedCookieApp");

    services.ConfigureApplicationCookie(options =>
    {
        options.Cookie.Name = "test";
        options.Cookie.Domain = ".localhost";
        options.Cookie.Path = "/";
    });
    
}

项目 B(REST API - 这里我们不只是要“消费”项目 A 中生成的 cookie):

public void ConfigureServices(IServiceCollection services)
{
    services.AddAuthentication(options =>
    {
        options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    })
    .AddCookie(options =>
    {
        options.Cookie.Name = "test";
        options.Cookie.Domain = ".localhost";
        options.Cookie.Path = "/";
        options.Events.OnRedirectToLogin = context =>
        {
            context.HttpContext.Response.StatusCode = StatusCodes.Status401Unauthorized;
            return Task.CompletedTask;
        };
    });

    services.AddDataProtection()
        .PersistKeysToFileSystem(new System.IO.DirectoryInfo("/cookies"))
        .SetApplicationName("SharedCookieApp");

    services.ConfigureApplicationCookie(options =>
    {
        options.Cookie.Name = "test";
        options.Cookie.Domain = ".localhost";
        options.Cookie.Path = "/";
        options.Events.OnRedirectToLogin = context =>
        {
            context.HttpContext.Response.StatusCode = StatusCodes.Status401Unauthorized;
            return Task.CompletedTask;
        };
    });
}

我得到的错误:

您引用的文档实际上包含您需要的一切。但这需要一些基本知识才能理解。要在另一个应用程序中使用由一个应用程序设置的 cookie,您需要确保两件事:

  1. cookie 应该发送到两个应用程序
    1.1.如果应用程序托管在同一域但不同路径上,则需要 set cookie Path 到公分母。例如,这里的公分母是 /:
    https://my-domain.com/app1
    https://my-domain.com/app2
    这里是/api(不过/也是有效的)
    https://my-domain.com/api/app1
    https://my-domain.com/api/app2
    1.2 如果应用托管在不同的域上,它们必须是某个公共域的子域。 Set cookie domain 到公共域值以在子域之间共享它。
    例如,这里的公共域是 .company.com:
    https://sub-domain1.company.com
    https://sub-domain2.company.com
    这也是常见域的示例 .company.com
    https://company.com
    https://sub-domain2.company.com
    但是这 2 个域 无法共享 cookie,因为它们没有公共域:
    https://sub-domain1.company1.com
    https://sub-domain2.company2.com
    1.3 如果您的应用托管在具有共同 sub-domain 和不同路径的不同域上,您还可以混合域和路径配置。例如,这里的域应该是 .company.com 和路径 /:
    https://sub-domain1.company.com/api/app1
    https://sub-domain2.company.com/app2

  2. 两个应用程序都可以解密 cookie 并理解其内容。
    2.1 如果应用托管在同一台机器上,您可以使用文件存储来保留数据保护密钥:

services.AddDataProtection()
    .PersistKeysToFileSystem("{PATH TO COMMON KEY RING FOLDER}")

2.2 如果应用程序托管在不同的机器上,您需要使用其他类型的存储,以便两个应用程序都能够访问它并读取保护密钥。例如,您可以使用 Amazon KMS service with Amazon.AspNetCore.DataProtection.SSM nuget:

services.AddDataProtection()
    .PersistKeysToAWSSystemsManager("/MyApplication/DataProtection");