сервер идентификации 4, различные варианты локального входа в систему / azure - PullRequest
0 голосов
/ 06 мая 2020

Среды: localhost / azure, .netcore 3.1 mvc identityserver4 + mvc api client.

Когда я запускаю свое приложение локально, вход / выход из системы работает нормально, есть: - identityserver4 mvc .netcore 3.1 - клиент mvc api .netcore 3.1

Я могу входить / выходить из системы сколько угодно, логин всегда перенаправляется на логин identityserver4, и логин работает.

Когда одно и то же приложение с identityserver4 размещено на Azure Первый логин правильно перенаправляет на azure identityserver4, и логин работает нормально. Затем после выхода из системы (кажется, что петлицы удалены), когда я снова пытаюсь войти в систему, перенаправление на страницу входа не работает, и происходит «неявный» вход и прямое перенаправление на домашнюю страницу веб-сайта.

Клиент mvc api настроен следующим образом:

{
  "ClientId": "IdentityServer.WebApi",
  "ClientSecret": "IdentityServer.WebApi",
  "AllowedGrantTypes": "GrantTypes.CodeAndClientCredentials",
  "RedirectUris": [
    "https://localhost:44372/signin-oidc",
    "https://localhost:5001/signin-oidc",
    "https://192.168.1.7:44372/signin-oidc",
    "https://mogui:44372/signin-oidc"
  ],
  "PostLogoutRedirectUris": [
    "https://localhost:44372/signout-callback-oidc",
    "https://localhost:5001/signout-callback-oidc",
    "https://192.168.1.7:44372/signout-callback-oidc",
    "https://mogui:44372/signout-callback-oidc"
  ],
  "AllowedScopes": [
    "openid",
    "profile"
  ],
  "RequireConsent": true,
  "RequirePkce": true,
  "AllowOfflineAccess": true
},

Сервер идентификации4 локально / на azure имеет такой код в своем классе запуска:

public void ConfigureServices(IServiceCollection services)
{
    try
    {
        telemetryClient.TrackTrace("============== Startup ConfigureServices ============== ");

        // uncomment, if you wan to add an MVC-based UI
        services.AddControllersWithViews();
        //services.AddMvc();

        string connectionString = Configuration.GetConnectionString("IdentityDbContextConnection");
        //const string connectionString = @"Data Source=(LocalDb)\MSSQLLocalDB;database=IdentityServer4.Quickstart.EntityFramework-3.0.102;trusted_connection=yes;";
        var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;

        services.AddDbContext<IdentityServer.Models.IdentityDbContext>(options =>
            options.UseSqlServer(connectionString, sql => sql.MigrationsAssembly(migrationsAssembly))
        );

        services.AddIdentity<ApplicationUser, IdentityRole>(options =>
        {
            options.SignIn.RequireConfirmedEmail = true;
        })
        .AddEntityFrameworkStores<IdentityServer.Models.IdentityDbContext>()
        .AddDefaultTokenProviders();

        services.AddMvc(options =>
        {
            options.EnableEndpointRouting = false;
        })
        .SetCompatibilityVersion(CompatibilityVersion.Latest);

        var builder = services.AddIdentityServer(options =>
        {
            options.Events.RaiseErrorEvents = true;
            options.Events.RaiseInformationEvents = true;
            options.Events.RaiseFailureEvents = true;
            options.Events.RaiseSuccessEvents = true;
            options.UserInteraction.LoginUrl = "/Account/Login";
            options.UserInteraction.LogoutUrl = "/Account/Logout";
            options.Authentication = new AuthenticationOptions()
            {
                CookieLifetime = TimeSpan.FromHours(10), // ID server cookie timeout set to 10 hours
                CookieSlidingExpiration = true
            };
        })
        .AddSigningCredential(X509.GetCertificate("B22BBE7C991CEF13F470481A4042D1E091967FCC"))   // signing.crt thumbprint
        .AddValidationKey(X509.GetCertificate("321ABA505F6FCDDD00AA5EC2BD307F0C9002F9A8"))       // validation.crt thumbprint
        .AddConfigurationStore(options =>
        {
            options.ConfigureDbContext = b => b.UseSqlServer(connectionString, sql => sql.MigrationsAssembly(migrationsAssembly));
        })
        .AddOperationalStore(options =>
        {
            options.ConfigureDbContext = b => b.UseSqlServer(connectionString, sql => sql.MigrationsAssembly(migrationsAssembly));
            options.EnableTokenCleanup = true;
        })
        .AddAspNetIdentity<ApplicationUser>();

        services.AddAuthentication()
        .AddGoogle("Google", options =>
        {
            options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;

            options.ClientId = "174637674775-7bgu471gtme25sr5iagq5agq6riottek.apps.googleusercontent.com";
            options.ClientSecret = "V_UsR825ZWxCB9i2xrN-u1Kj";
        });

        services.AddTransient<IEmailSender, IdentityEmailSender>();

        services.AddCors(options => options.AddPolicy("AllowAll", p => p.AllowAnyOrigin()
        .AllowAnyMethod()
        .AllowAnyHeader()));

        services.Configure<CookiePolicyOptions>(options =>
        {
            options.CheckConsentNeeded = context => true;
            options.MinimumSameSitePolicy = SameSiteMode.Strict;
        });

        services.AddScoped<IProfileService, ProfileService>();

        telemetryClient.TrackTrace("============== Startup ConfigureServices finish OK ============== ");

    }
    catch (Exception e)
    {
        telemetryClient.TrackTrace("Exception general in ConfigureServices");
        telemetryClient.TrackException(e);
        throw;
    }
}

и это:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    try
    {
        telemetryClient.TrackTrace("============== Startup Configure ============== ");

        InitializeDatabase(app);

        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseStaticFiles();
        app.UseCors("AllowAll");
        app.UseRouting();

        app.UseIdentityServer();
        app.UseAuthorization();

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

        app.UseMvcWithDefaultRoute();

        app.UseMvc(routes =>
        {
            routes.MapRoute(
                   name: "default",
                   template: "{controller=Home}/{action=Index}/{id?}");
        });

        telemetryClient.TrackTrace("============== Startup Configure finish OK============== ");
    }
    catch (Exception e)
    {
        telemetryClient.TrackTrace("Exception general in Configure");
        telemetryClient.TrackException(e);
        throw;
    }
}

Итак, проблема с

localhost identityserver4, вход / выход работает, найдите

idnetityserver4, размещенный на azure, вход в систему пропускается и go прямо на домашнюю страницу (пользователь аутентифицирован при предыдущем входе в систему).

Извините, что немного долго, я не видел этой точной проблемы в stackoverflow или где-то еще.

Заранее спасибо!

Ответы [ 2 ]

0 голосов
/ 26 мая 2020

Ты прав, Рист, согласно разным сообщениям, которые я видел, мы можем сделать такую ​​вещь:

- first of all, we have to put FrontChannelLogoutUri parameter 

(это должен быть mvc клиентский контроллер / действие, вызываемое identityserver4, в нашем случае это должно быть что-то вроде https://localhost: 999 / Account / FrontChannelLogout ) для клиентского приложения mvc, обычно оно помещается в Config.cs и добавляет этот параметр для клиента Mvc ( с RedirectUris, PostLogoutRedirectUris, ...)

- on the client mvc, in an account controller (for instance) where is managed the login , 

мы можем добавить / изменить управление выходом из системы:

[Authorize]
public async Task<IActionResult> Logout()
{
    var client = new HttpClient();

    var disco = await client.GetDiscoveryDocumentAsync($"https://{Startup.Configuration["Auth0:Domain"]}");

    return Redirect(disco.EndSessionEndpoint);
}

public async Task<IActionResult> FrontChannelLogout(string sid)
{
    if (User.Identity.IsAuthenticated)
    {
        var currentSid = User.FindFirst("sid")?.Value ?? "";
        if (string.Equals(currentSid, sid, StringComparison.Ordinal))
        {
            await HttpContext.SignOutAsync("oidc");
            await HttpContext.SignOutAsync("Identity.Application");
            await _signInManager.Context.SignOutAsync("_af");
            await _signInManager.Context.SignOutAsync("idsrv.session");
            await _signInManager.Context.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
        }
    }

    return NoContent();
}

На стороне identityserver4:

В QuickStart Контроллер учетной записи, мы должны обновить метод BuildLoggedOutViewModelAsyn c:

    private async Task<LoggedOutViewModel> BuildLoggedOutViewModelAsync(string logoutId)
    {
        // get context information (client name, post logout redirect URI and iframe for federated signout)
        var logout = await _interaction.GetLogoutContextAsync(logoutId);

        var client = await _clientStore.FindEnabledClientByIdAsync(logout.ClientIds.First());

        if (!string.IsNullOrEmpty(client.FrontChannelLogoutUri))
        {
            //var pos = GetNthIndex(client.FrontChannelLogoutUri, '/', 3);
            //logout.PostLogoutRedirectUri = client.FrontChannelLogoutUri.Substring(0, Math.Min(client.FrontChannelLogoutUri.Length, pos));
            // Here TODO =====> get the real PostLogoutRedirectUri, it should be a controller/action url on the client mvc side and put it in **logout.PostLogoutRedirectUri**
        }

        var vm = new LoggedOutViewModel
        {
            AutomaticRedirectAfterSignOut = AccountOptions.AutomaticRedirectAfterSignOut,
            PostLogoutRedirectUri = logout?.PostLogoutRedirectUri,
            ClientName = string.IsNullOrEmpty(logout?.ClientName) ? logout?.ClientId : logout?.ClientName,
            SignOutIframeUrl = logout?.SignOutIFrameUrl,
            LogoutId = logoutId
        };

        if (User?.Identity.IsAuthenticated == true)
        {
            var idp = User.FindFirst(JwtClaimTypes.IdentityProvider)?.Value;
            if (idp != null && idp != IdentityServer4.IdentityServerConstants.LocalIdentityProvider)
            {
                var providerSupportsSignout = await HttpContext.GetSchemeSupportsSignOutAsync(idp);
                if (providerSupportsSignout)
                {
                    if (vm.LogoutId == null)
                    {
                        // if there's no current logout context, we need to create one
                        // this captures necessary info from the current logged in user
                        // before we signout and redirect away to the external IdP for signout
                        vm.LogoutId = await _interaction.CreateLogoutContextAsync();
                    }

                    vm.ExternalAuthenticationScheme = idp;
                }
            }
        }

        return vm;
    }

====> Очевидно, _interaction.GetLogoutContextAsyn c (logoutId) никогда не возвращает PostLogoutRedirectUri, даже если он был настроен для клиент mvc (в Config.cs).

====> заполнив этот параметр logout.PostLogoutRedirectUri на стороне identityServer4, он перенаправит выход из системы в клиентское приложение.

Вот что я могу сказать: я не знаю, является ли перенаправление выхода из системы в клиентское приложение «стандартным» поведением, не знаю, планировалось ли это в identityserver4.

Некоторые ссылки :

https://andersonnjen.com/2019/03/22/identityserver4-global-logout/ Как перенаправить пользователя в клиентское приложение после выхода с сервера идентификации?

Thanx!

0 голосов
/ 24 мая 2020
• 1000 1016 * ("Cookies) call.

Проверьте следующее:

  1. PostLogoutRedirectUris содержит ваш azure домен +" signout-callback-oid c "
  2. Проверьте, по какому пути создаются ваши файлы cookie аутентификации. Если он отличается от "/" - добавьте путь по умолчанию. Я думаю, в вашем случае он будет чем-то вроде среди строк:

    options.Authentication = new AuthenticationOptions()
    {
        CookieLifetime = TimeSpan.FromHours(10), // ID server cookie timeout set to 10 hours
        CookieSlidingExpiration = true,
        Path = "/"
    };
    
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...