配置身份服务器时出错。 cookie '.AspNetCore.Identity.Application' 已设置 'SameSite=None' 并且还必须设置 'Secure'

问题描述 投票:0回答:1

我正在尝试学习IdentityServer4。我在 IdentityServer 中设置一个项目,在 MVC 中设置另一个项目。代码在本地主机中按预期运行,但我在 docker swarm 环境中遇到错误。使用正确的用户名密码成功登录后,它会再次重定向到登录页面。 mvc的程序cs如下:

using System.Security.Claims;
using DMNMiddleware.UserManagement.Services;
using IdentityModel.Client;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.EntityFrameworkCore;
using Microsoft.IdentityModel.Tokens;
using Npgsql;

var builder = WebApplication.CreateBuilder(args);
builder.Configuration
    .SetBasePath(Directory.GetCurrentDirectory())
    .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
    .AddJsonFile($"appsettings.{builder.Environment.EnvironmentName}.json", optional: true)
    .AddEnvironmentVariables();

string authUrl = builder.Configuration.GetValue<string>("AuthServerUrl") ?? string.Empty;
string interceptUrl = builder.Configuration.GetValue<string>("AuthInterceptUrl") ?? string.Empty;
builder.Services.AddControllersWithViews();

var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");

builder.Services.AddAuthentication(options =>
{
    options.DefaultScheme = "Cookies";
    options.DefaultChallengeScheme = "oidc";

}).AddCookie("Cookies", c =>
{
    c.CookieManager = new ChunkingCookieManager();
    c.Cookie.HttpOnly = true;
    c.Cookie.SameSite = SameSiteMode.None;
    c.Cookie.SecurePolicy = CookieSecurePolicy.SameAsRequest;
    c.ExpireTimeSpan = TimeSpan.FromMinutes(30);
})
.AddOpenIdConnect("oidc", options =>
{

    options.Authority = authUrl;
    options.MetadataAddress = $"{authUrl}/.well-known/openid-configuration";
    options.Events.OnRedirectToIdentityProvider = context =>
    {
        // Intercept the redirection so the browser navigates to the right URL in your host
        context.ProtocolMessage.IssuerAddress = $"{interceptUrl}/connect/authorize";
        return Task.CompletedTask;
    };
    options.RequireHttpsMetadata = false;
    options.GetClaimsFromUserInfoEndpoint = true;
    options.ClientId = "usermanagement";
    options.ClientSecret = "secret";
    options.ResponseType = "code";
    options.Scope.Add("usermanagement");
    options.Scope.Add("openid");
    options.Scope.Add("profile");
    options.SaveTokens = true;
    options.TokenValidationParameters = new TokenValidationParameters
    {
        NameClaimType = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name",  // Explicitly set the correct name claim type
        RoleClaimType = "http://schemas.microsoft.com/ws/2008/06/identity/claims/role"
    };
    options.ClaimActions.MapJsonKey(ClaimTypes.Name, "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name");
    options.ClaimActions.MapJsonKey(ClaimTypes.Role, "http://schemas.microsoft.com/ws/2008/06/identity/claims/role");
    options.NonceCookie.SecurePolicy = CookieSecurePolicy.SameAsRequest;
    options.CorrelationCookie.SecurePolicy = CookieSecurePolicy.SameAsRequest;
});


builder.Services.AddDataProtection()
    .PersistKeysToFileSystem(new DirectoryInfo(@"/root/.aspnet/DataProtection-Keys"))
    .SetApplicationName("SharedApp");


builder.Services.AddHttpContextAccessor();

builder.Services.AddScoped<NpgsqlConnection>(sp =>
{
    var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
    return new NpgsqlConnection(connectionString);
});

builder.Services.AddScoped<IUserService, UsersService>();
builder.Services.AddScoped<IEndPointService, EndPointService>();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Home/Error");
    app.UseHsts();
}
app.UseCookiePolicy();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();

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

app.Run();

身份服务器的program.cs如下:

using DMNMiddleware.AuthServer;
using DMNMiddleware.AuthServer.Data;
using DMNMiddleware.AuthServer.DomainModels;
using DMNMiddleware.AuthServer.Profiles;
using DMNMiddleware.AuthServer.Services;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using StackExchange.Redis;

var builder = WebApplication.CreateBuilder(args);
builder.Configuration
    .SetBasePath(Directory.GetCurrentDirectory()) 
    .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) 
    .AddJsonFile($"appsettings.{builder.Environment.EnvironmentName}.json", optional: true) 
    .AddEnvironmentVariables();
builder.Services.AddControllersWithViews();
//database connection
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");

builder.Services.AddDbContext<AuthServerDbContext>(options => 
options.UseNpgsql(connectionString));

//Add Identity
builder.Services.AddIdentity<ApplicationUser, IdentityRole>()
                .AddEntityFrameworkStores<AuthServerDbContext>()
                .AddDefaultTokenProviders();

// Configure IdentityServer4
builder.Services.AddIdentityServer(options =>
                {
                    options.Authentication.CookieAuthenticationScheme = IdentityConstants.ApplicationScheme;
                })
                .AddInMemoryClients(Config.Clients)
                .AddInMemoryIdentityResources(Config.IdentityResources)
                .AddInMemoryApiScopes(Config.ApiScopes)
                .AddAspNetIdentity<ApplicationUser>()
                .AddProfileService<IdentityProfileService>()
                .AddDeveloperSigningCredential();

builder.Services.ConfigureApplicationCookie(options =>
{
    options.Cookie.SameSite = SameSiteMode.None;
    options.Cookie.SecurePolicy = CookieSecurePolicy.SameAsRequest;
});

builder.Services.AddHttpContextAccessor();

builder.Services.AddScoped<IDbInitializer, DbInitializer>();
builder.Services.AddScoped<IAccountService, AccountService>();
builder.Services.AddScoped<IUsersService, UsersService>();
builder.Services.AddScoped<IEndPointService, EndPointService>();

builder.Services.AddDataProtection()
    .PersistKeysToFileSystem(new DirectoryInfo(@"/root/.aspnet/DataProtection-Keys"))
    .SetApplicationName("SharedApp");


builder.Services.AddAntiforgery();
    
var app = builder.Build();
app.UseStaticFiles();
app.UseRouting();

app.UseIdentityServer();
app.UseAuthorization();
app.Use(async (context, next) =>
{
    context.Response.Headers.Append("Content-Security-Policy", "default-src 'self'; style-src 'self' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com;");
    await next();
});
using(var scope = app.Services.CreateScope())
{
    var dbInitializer = scope.ServiceProvider.GetRequiredService<IDbInitializer>();
    dbInitializer.Initialize();
}

app.UseEndpoints(endpoints => {
    _ = endpoints.MapDefaultControllerRoute();
});

app.Run();

我的docker堆栈文件如下

version: '3.8'

services:
  authserver:
    image: 192.168.48.107:5000/dmn/authserver:1.0.0
    ports:
      - "7000:80"
    networks:
      - my_network
    deploy:
      replicas: 1
      restart_policy:
        condition: on-failure
    volumes:
      - key-storage:/root/.aspnet/DataProtection-Keys




  usermanagement:
    image: 192.168.48.107:5000/dmn/usermanagement:1.0.0
    ports:
      - "9000:80"
    networks:
      - my_network
    deploy:
      replicas: 1
      restart_policy:
        condition: on-failure
    volumes:
      - key-storage:/root/.aspnet/DataProtection-Keys

networks:
  my_network:
    driver: overlay

volumes:
  key-storage:
  redis-data:

我目前正在两个program.cs中使用cookie设置,但没有按预期工作。 我的config.cs文件如下:

using System.Security.Claims;
using IdentityServer4;
using IdentityServer4.Models;

namespace DMNMiddleware.AuthServer;

public class Config
{

    public static IEnumerable<Client> Clients => new Client[]
    {
        new Client
        {
            ClientId = "api_client",
            AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
            ClientSecrets = 
            {
                new Secret("client_secret".Sha256())
            },
            AllowedScopes = {"api_scope"}
        },
        new Client
        {
            ClientId = "usermanagement",
            ClientSecrets = { new Secret("secret".Sha256()) },
            AllowedGrantTypes = GrantTypes.Code,
            RedirectUris = {
                "http://localhost:9000/signin-oidc", 
                "http://192.168.48.107:9000/signin-oidc",
                "http://192.168.48.108:9000/signin-oidc",
                "http://192.168.48.109:9000/signin-oidc"
             },
            PostLogoutRedirectUris = { 
                "http://localhost:9000/signout-callback-oidc",
                "http://192.168.48.107:9000/signout-callback-oidc", 
                "http://192.168.48.108:9000/signout-callback-oidc",
                "http://192.168.48.109:9000/signout-callback-oidc" 
            },
            AllowedScopes = new List<string>
            {
                IdentityServerConstants.StandardScopes.OpenId,
                IdentityServerConstants.StandardScopes.Profile,
                IdentityServerConstants.StandardScopes.Email,
                "usermanagement"
            },
            RequireConsent = false
        },
    };

    public static IEnumerable<ApiScope> ApiScopes => new ApiScope[]
    {
        new ApiScope("api_scope","api_scope"),
        new ApiScope("usermanagement", "usermanagement")
    };

    public static IEnumerable<ApiResource> ApiResources => new ApiResource[]
    {

    };

    public static IEnumerable<IdentityResource> IdentityResources => 
    new IdentityResource[]
    {
      new IdentityResources.OpenId(),
      new IdentityResources.Profile(),
      new IdentityResources.Address(),
      new IdentityResources.Email(),
      new IdentityResource(
        "roles",
        "",
        new List<string>() {"role"}
      ),


    };
}


asp.net-mvc asp.net-core cookies identityserver4
1个回答
0
投票

您必须在浏览器和服务之间使用 HTTPS,包括 RedirectUris ,但在容器之间使用 HTTP 是可以的。

SameSite=none cookie 需要 HTTPS 才能工作。

我使用 Docker Compose 和 IdentityServer 做了一个示例项目,您可以在这里找到我的代码 https://github.com/tndataab/PublicBlogContent/tree/main/IdentityServer-in-Docker(查看 Final 文件夹)。

该代码将在即将发布的博客文章中使用。

那么,我认为你需要在这里使用Lax,因为浏览器会拒绝这里的Strict cookies:

c.Cookie.SameSite = SameSiteMode.None;

它可能会被浏览器阻止。如果您想了解有关如何调试 ASP.NET Core 中的 cookie 问题的更多信息,请参阅我的博客文章:https://nestenius.se/2023/10/09/debugging-cookie-problems/

最新问题
© www.soinside.com 2019 - 2024. All rights reserved.