Бесконечный круговой редирект с IdentityServer4 - PullRequest
0 голосов
/ 29 ноября 2018

Я разрабатываю мультитенантное приложение ASP.NET MVC, используя Finbuckle.Multitenant и IdentityServer4 (используя стандартные классы и контроллеры из их учебных пособий).Мое приложение использует стратегию маршрутизации для арендаторов (https://host/tenant1/controller/action), и я использую отдельные куки для каждого арендатора (куки с именем auth.tenant1 , auth.tenant2 ... и т. Д.)Все работает нормально, если я не укажу собственный путь для куки-файла auth. Если у всех из них есть Path = / , то все в порядке. НО, когда я устанавливаю Path = / tenant1 в файл cookie с именем auth.tenant1и тот же шаблон для всех остальных арендаторов. У меня есть круговые перенаправления после прохождения экрана согласия. Когда я нажимаю «да» на экране согласия, я получаю перенаправление вызова 302. из промежуточного программного обеспечения IdentityServer на стороне клиента. Оно перенаправляет меня обратно на экран согласия. После каждого «да "Я возвращаюсь к согласию. Однако это происходит только во время процесса аутентификации. Если я открою новую вкладку и зайду на https://host/tenant1, я не буду перенаправлен и буду успешно аутентифицирован. Гуглил ответы в течение нескольких дней, но убежищеНе найдено никаких решений. Пожалуйста, помогите мне!

Вот мой Startup.cs моего * клиента:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc();

        JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();

        services.AddMultiTenant().WithInMemoryStore(Configuration.GetSection("MultiTenant:InMemoryStore"))
            .WithRouteStrategy(MapRoutes)
            .WithRemoteAuthentication()
            .WithPerTenantOptions<AuthenticationOptions>((options, tenantContext) =>
            {
                // Allow each tenant to have a different default challenge scheme.
                if (tenantContext.Items.TryGetValue("ChallengeScheme", out object challengeScheme))
                {
                    options.DefaultChallengeScheme = (string)challengeScheme;
                }
            })
            .WithPerTenantOptions<CookieAuthenticationOptions>((options, tenantContext) =>
            {
                options.Cookie.Name += tenantContext.Identifier;
                options.Cookie.Path = "/" + tenantContext.Identifier;
                options.LoginPath = "/" + tenantContext.Identifier + "/Home/Login";
            });

        services.AddAuthentication(options =>
        {
            options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            options.DefaultChallengeScheme = "oidc";
        })
        .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, o =>
            {
                o.Cookie.Name = "auth.";
            })
        .AddOpenIdConnect("oidc", options =>
        {
            options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            options.Authority = "https://localhost:5000";
            options.RequireHttpsMetadata = true;

            options.ClientId = "mvc";
            options.SaveTokens = true;

            options.ClientSecret = "secret";
            //Hybrid protocols (OpenId + OAuth)
            options.ResponseType = OpenIdConnectResponseType.CodeIdToken;

            options.GetClaimsFromUserInfoEndpoint = true;
            //ask to allow access to testApi
            options.Scope.Add("testApi");
            //allows requesting refresh tokens for long lived API access
            options.Scope.Add("offline_access");

            options.Events = new OpenIdConnectEvents()
            {
                OnRedirectToIdentityProvider = ctx =>
                {
                    var tenant = ctx.HttpContext.GetMultiTenantContext()?.TenantInfo?.Identifier;
                    ctx.ProtocolMessage.AcrValues = $"tenant:{tenant}";
                    return Task.FromResult(0);
                }
            };
        });
    }

    private void MapRoutes(IRouteBuilder router)
    {
        router.MapRoute("Default", "{__tenant__=tenant1}/{controller=Home}/{action=Index}/{id?}");
    }

Вот мой клиентский конфигРуководство IdentityServer (appsettings.json):

{
  "clientId": "mvc",
  "clientName": "MVC Client",
  "allowedGrantTypes": [ "hybrid", "client_credentials" ],
  "clientSecrets": [
    { "value": "K7gNU3sdo+OL0wNhqoVWhr3g6s1xYv72ol/pe/Unols=" } // Sha256("secret")
  ],
  "redirectUris": [ "https://localhost:5002/signin-oidc" ],
  "postLogoutRedirectUris": [ "https://localhost:5002/signout-callback-oidc" ],
  "allowedScopes": [ "openid", "profile", "testApi" ],
  "allowOfflineAccess": true
},

Мой конфиг IdentityServer4:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc();

        var identityServerBuilder = services.AddIdentityServer()
            .AddDeveloperSigningCredential();

        if (_config.GetSection("AppSettings:UseDummyAuthentication").Get<bool>())
        {
            identityServerBuilder
                .AddInMemoryIdentityResources(_config.GetSection("IdentityResources"))
                .AddInMemoryApiResources(_config.GetSection("ApiResources"))
                .AddInMemoryClients(_config.GetSection("Clients"))
                .AddTestUsers(_config.GetSection("TestUsers"));
        }

        services.AddAuthentication();
    }

Пожалуйста, помогите мне, ребята!Как сделать так, чтобы схема Path = / tenant1 работала без перенаправлений на экране согласия ???

1 Ответ

0 голосов
/ 03 декабря 2018

Хорошо, я разобрался, что не так, и опубликовал ответ тем, кто столкнется с той же проблемой.Проблема заключается в том, что при изменении пути cookie промежуточное программное обеспечение IdentityServer не может его найти, потому что оно размещено на https://host/signin-oidc/.. Для этого необходимо обработать https://host/tenant1/signin-oidc для каждого клиента на клиенте и добавить всеэти URL-адреса клиентов redirectUris.Для этого ваша мультитенантная конфигурация должна выглядеть следующим образом

            services.AddMultiTenant().WithInMemoryStore(Configuration.GetSection("MultiTenant:InMemoryStore"))
            .WithRouteStrategy(MapRoutes)
            .WithRemoteAuthentication()
            .WithPerTenantOptions<CookieAuthenticationOptions>((options, tenantContext) =>
            {
                options.Cookie.Name = $"auth.{tenantContext.Identifier}";
                options.Cookie.Path = "/" + tenantContext.Identifier;
                options.LoginPath = "/" + tenantContext.Identifier + "/Home/Login";
            })
            .WithPerTenantOptions<OpenIdConnectOptions>((opt, ctx) =>
            {
                opt.CallbackPath = "/" + ctx.Identifier + "/signin-oidc";
            });

Whole Startup.cs

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.AddMvc();

        JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();

        services.AddMultiTenant().WithInMemoryStore(Configuration.GetSection("MultiTenant:InMemoryStore"))
            .WithRouteStrategy(MapRoutes)
            .WithRemoteAuthentication()
            .WithPerTenantOptions<CookieAuthenticationOptions>((options, tenantContext) =>
            {
                options.Cookie.Name = $"auth.{tenantContext.Identifier}";
                options.Cookie.Path = "/" + tenantContext.Identifier;
                options.LoginPath = "/" + tenantContext.Identifier + "/Home/Login";
            })
            .WithPerTenantOptions<OpenIdConnectOptions>((opt, ctx) =>
            {
                opt.CallbackPath = "/" + ctx.Identifier + "/signin-oidc";
            }); ;

        services.AddAuthentication(options =>
        {
            options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            options.DefaultChallengeScheme = "oidc";
        })
        .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, o =>
            {
                o.Cookie.Name = "auth.";
                o.Cookie.IsEssential = true;
            })
        .AddOpenIdConnect("oidc", options =>
        {
            options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            options.Authority = "https://localhost:5000";

            options.ClientId = "mvc";
            options.SaveTokens = true;

            options.ClientSecret = "secret";
            //Hybrid protocols (OpenId + OAuth)
            options.ResponseType = OpenIdConnectResponseType.CodeIdToken;

            options.GetClaimsFromUserInfoEndpoint = true;
            //ask to allow access to testApi
            options.Scope.Add("testApi");
            //allows requesting refresh tokens for long lived API access
            options.Scope.Add("offline_access");

            options.Events = new OpenIdConnectEvents()
            {
                OnRedirectToIdentityProvider = ctx =>
                {
                    var tenant = ctx.HttpContext.GetMultiTenantContext()?.TenantInfo?.Identifier;
                    ctx.ProtocolMessage.AcrValues = $"tenant:{tenant}";
                    return Task.FromResult(0);
                }
            };
        });
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseBrowserLink();
            app.UseDeveloperExceptionPage();
        }
        else
        {
            var errorPage = Configuration.GetValue<string>("ErrorPage");
            app.UseExceptionHandler(errorPage);
            app.UseHsts();
        }
        app.UseHttpsRedirection();
        app.UseStaticFiles();
        app.UseMultiTenant();
        app.UseAuthentication();
        app.UseMvc(MapRoutes);
    }

    private void MapRoutes(IRouteBuilder router)
    {
        router.MapRoute("Default", "{__tenant__=tenant1}/{controller=Home}/{action=Index}/{id?}");
    }

Не забудьте зарегистрировать все URL арендаторов в IdentityServer4 Client.RedirecUris

"redirectUris": [ "https://localhost:5002/tenant1/signin-oidc", "https://localhost:5002/tenant2/signin-oidc", "https://localhost:5002/tenant3/signin-oidc" ]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...