#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);
}
}
});
}