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,您需要确保两件事:
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
两个应用程序都可以解密 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");
这是一个与概念方法有关的问题。
所以我有两个项目 - 其中一个已经实施了身份验证并且工作正常。这是一个带有 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,您需要确保两件事:
cookie 应该发送到两个应用程序
1.1.如果应用程序托管在同一域但不同路径上,则需要 set cookiePath
到公分母。例如,这里的公分母是/
:
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两个应用程序都可以解密 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");