Тайм-аут cookie-файла аутентификации при использовании OpenID Connect в ASP.NET Веб-формы

#asp.net #webforms #azure-active-directory #openid-connect

#asp.net #веб-формы #azure-active-directory #OpenID-подключение

Вопрос:

В целях обучения и ускорения работы с OpenID Connect я пытаюсь добавить аутентификацию и авторизацию в устаревшее приложение веб-форм, используя Azure AD в качестве сервера аутентификации.

Я застрял на одном аспекте в течение нескольких дней и не могу добиться никакого прогресса. Я хотел бы сделать что-то, что, по моему мнению, должно быть простым. В отличие от большинства, я хочу, чтобы приложение отключило время ожидания и перенаправило пользователя обратно на логин Azure. В идеале я хотел бы контролировать этот тайм-аут из самой конфигурации приложения. Кажется, все спрашивают, как не указывать на вход в систему по истечении срока действия, но я хочу сделать это в учебных целях и просто знать, что я могу контролировать это.

Моя «проблема» заключается в том, что когда срок действия cookie-файла аутентификации истекает (или удаляется из браузера), мой запрос.Проверка подлинности IsAuthenticated никогда не завершается ошибкой, и токены просто обновляются. Я никогда не могу заставить его принудительно войти в систему. Я чувствую, что перепробовал все и не могу найти какой-либо срок действия, который что-либо значит. Я даже не знаю, как обновляются токены.

Я поместил этот код в базовый класс страницы. Я ожидал бы, что в какой-то момент срок действия cookie-файла аутентификации истечет, и эта логика кода вызовет вызов, подобный тому, который возникает при первом запуске приложения. Я пробовал здесь разные вещи. Это может привести к сокращению времени до обновления токенов, но оно никогда не истекает.

 private void Page_PreInit(object sender, EventArgs e)
    {

        if (!Request.IsAuthenticated)
        {
            HttpContext.Current.GetOwinContext().Authentication.Challenge(
                 new AuthenticationProperties
                 {
                     RedirectUri = "/",
                     IsPersistent = true,
                     //ExpiresUtc = DateTime.UtcNow.AddMinutes(1)
                 },
                 OpenIdConnectAuthenticationDefaults.AuthenticationType); ;
            Response.End();
        }

    }
 

И конфигурация запуска:

   public partial class Startup
{

    public void ConfigureAuth(IAppBuilder app)
    {
        app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);

        app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationType = "Cookies",
            CookieManager = new Microsoft.Owin.Host.SystemWeb.SystemWebChunkingCookieManager(),
            
            //ExpireTimeSpan = new TimeSpan(0, 1, 0),
            SlidingExpiration = false,

            //Provider = new CookieAuthenticationProvider
            //{
            //    OnResponseSignIn = context =>
            //    {
            //        context.Properties.AllowRefresh = false;
            //        context.Properties.ExpiresUtc = DateTimeOffset.UtcNow.AddMinutes(1);
            //    },

            //}

        });

        app.UseOpenIdConnectAuthentication(
        new OpenIdConnectAuthenticationOptions
        {
            ClientId = AuthenticationConfig.ClientId,
            ClientSecret = AuthenticationConfig.ClientSecret,
            Authority = AuthenticationConfig.Authority,
            RedirectUri = AuthenticationConfig.RedirectUri,
            PostLogoutRedirectUri = AuthenticationConfig.PostLogoutRedirectUri,

            Scope = AuthenticationConfig.BasicSignInScopes   ' '  
                     AuthenticationConfig.APIResourceUri   "access_as_user",


            SignInAsAuthenticationType = "cookie",

            RequireHttpsMetadata = false,
            UseTokenLifetime = true, // Needed to override default and allow custom auth cookie timout

            RedeemCode = true,
            SaveTokens = true,

            ResponseType = OpenIdConnectResponseType.Code,
            ResponseMode = "query",

            // ValidateIssuer set to false to allow personal and work accounts from any organization to sign in to your application
            // To only allow users from a single organizations, set ValidateIssuer to true and 'tenant' setting in web.config to the tenant name
            // To allow users from only a list of specific organizations, set ValidateIssuer to true and use ValidIssuers parameter
            TokenValidationParameters = new TokenValidationParameters()
            {
                ValidateIssuer = true, // This is a simplification
                NameClaimType = AuthenticationConfig.NameClaimType,
                RoleClaimType = AuthenticationConfig.RoleClaimType
            },


            Notifications = new OpenIdConnectAuthenticationNotifications()
            {
                SecurityTokenValidated = Startup.SecurityTokenValidated
            }

        });

        // This makes any middleware defined above this line run before the Authorization rule is applied in web.config
        app.UseStageMarker(PipelineStage.Authenticate);
    }

    public static Task SecurityTokenValidated(SecurityTokenValidatedNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> notification)
    {
        var identity = notification.AuthenticationTicket.Identity;

        identity.AddClaim(claim: new Claim(type: "expires_at", value: notification.ProtocolMessage.ExpiresIn));
        identity.AddClaim(claim: new Claim(type: "id_token", value: notification.ProtocolMessage.IdToken));
        identity.AddClaim(claim: new Claim(type: "access_token", value: notification.ProtocolMessage.AccessToken));
        identity.AddClaim(claim: new Claim(type: "refresh_token", value: notification.ProtocolMessage.RefreshToken));

        return Task.CompletedTask;
    }

    private static string EnsureTrailingSlash(string value)
    {
        if (value == null)
        {
            value = string.Empty;
        }

        if (!value.EndsWith("/", StringComparison.Ordinal))
        {
            return value   "/";
        }

        return value;
    }
}
 

Я хотел бы знать, как сделать так, чтобы срок действия аутентификации истек, что приводит к перенаправлению входа в систему. Мое единственное предположение здесь заключается в том, что middlewhere действует до запуска кода предварительной инициализации. Если в этом что-то есть, то где я могу сделать такую проверку?

Комментарии:

1. Одна мысль, вы могли бы автоматически войти в систему, потому что у вас может быть действительный сеанс с IdentityProvider. поэтому, когда ваш локальный сеанс истекает, промежуточное программное обеспечение может попытаться попросить вас снова войти в систему, но если у вас там действительный сеанс, вы можете снова автоматически войти в систему.

2. Да, я действительно думаю, что в этом суть. В Azure при первом входе в систему я никогда не выбираю опцию запомнить (или как бы она ни была сформулирована). Я бы чувствовал себя лучше в своем понимании этого, если бы мог найти способ заставить его войти в систему.

3. Вы можете попытаться установить следующее, чтобы заставить поставщика удостоверений принудительно заставлять пользователя соглашаться с запрошенными областями, когда клиенты пытаются повторно пройти проверку подлинности: … Добавить OpenIdConnect(параметры => { … Опции. Приглашение = «согласие»; });

4. Итак, моя проблема заключалась в том, что я не мог понять, как локально выйти из системы, и я действительно не понимал, что это то, что мне нужно было сделать. Для локального выхода из системы все, что мне нужно сделать, это: // Только локальный выход! HttpContext.Current. GetOwinContext().Проверка подлинности. Выход из системы (CookieAuthenticationDefaults. AuthenticationType); Теперь я понимаю различные уровни выхода из системы и как их вызывать.

Ответ №1:

Я не уверен, что вы когда-либо решали эту проблему, но вот наша конфигурация, которая автоматически перенаправляет пользователя, когда он не проходит проверку подлинности.

     public void ConfigureAuth(IAppBuilder app)
    {
        var secrets = DIFactory.GetInstance<IApplicationSecrets>();
        
        var clientId = secrets.Ida_ClientId().Result;
        var aadInstance = secrets.Ida_AADInstance().Result;
        var tenantId = secrets.Ida_TenantId().Result;

        var authority = string.Format(CultureInfo.InvariantCulture, aadInstance, tenantId);
        
        /* Set authentication type to "Cookies" */
        app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
        
        /* Add a cookie-based authentication middleware to the OWIN pipeline */
        app.UseCookieAuthentication(
            new CookieAuthenticationOptions
            {
                CookieName = "RemoteAuthCookie",
                AuthenticationType = "Cookies",
                CookieSecure = CookieSecureOption.Always,
                ExpireTimeSpan = TimeSpan.FromMinutes(2.0),
                SlidingExpiration = false,
                CookieSameSite = SameSiteMode.None,
                CookieManager = new SystemWebCookieManager(), // new SameSiteCookieManager(new SystemWebCookieManager()),
            });

        app.UseOpenIdConnectAuthentication(
            new OpenIdConnectAuthenticationOptions
            {
                ClientId = clientId,
                Authority = authority,
                Scope = "openid profile",
                
                //CookieManager = new SameSiteCookieManager(new SystemWebCookieManager()),

                    // ResponseType is set to request the id_token - which contains basic information about the signed-in user
                ResponseType = OpenIdConnectResponseTypes.IdToken,
                Notifications = new OpenIdConnectAuthenticationNotifications
                {
                    RedirectToIdentityProvider = (context) =>
                    {
                        // This ensures that the address used for sign in and sign out is picked up dynamically from the request
                        var currentUrl = context.Request.Scheme   "://"   context.Request.Host   context.Request.Path;
                        context.ProtocolMessage.RedirectUri = currentUrl;
                        return Task.FromResult(0);
                    }
                }
            });
    }