FormsAuthentication.Функция SignOut() не выводит пользователя из системы

StackOverflow https://stackoverflow.com/questions/412300

  •  03-07-2019
  •  | 
  •  

Вопрос

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

FormsAuthentication.SignOut();
Session.Abandon();
FormsAuthentication.RedirectToLoginPage();

Но это не так.Если я введу URL-адрес напрямую, я все равно смогу перейти на нужную страницу.Я давно не пользовался функцией roll-your-own security, поэтому забыл, почему это не работает.

Это было полезно?

Решение

Пользователи по-прежнему могут просматривать ваш веб-сайт, поскольку файлы cookie не очищаются при вызове FormsAuthentication.SignOut () , и они аутентифицируются при каждом новом запросе. В документации MS написано, что cookie будет очищен, но это не так, ошибка? То же самое с Session.Abandon () , cookie все еще там.

Вы должны изменить свой код на это:

FormsAuthentication.SignOut();
Session.Abandon();

// clear authentication cookie
HttpCookie cookie1 = new HttpCookie(FormsAuthentication.FormsCookieName, "");
cookie1.Expires = DateTime.Now.AddYears(-1);
Response.Cookies.Add(cookie1);

// clear session cookie (not necessary for your current problem but i would recommend you do it anyway)
SessionStateSection sessionStateSection = (SessionStateSection)WebConfigurationManager.GetSection("system.web/sessionState");
HttpCookie cookie2 = new HttpCookie(sessionStateSection.CookieName, "");
cookie2.Expires = DateTime.Now.AddYears(-1);
Response.Cookies.Add(cookie2);

FormsAuthentication.RedirectToLoginPage();

HttpCookie находится в пространстве имен System.Web . Справочник по MSDN .

Другие советы

Похоже, у вас не настроен раздел авторизации web.config. Ниже приведен пример.

<authentication mode="Forms">
  <forms name="MyCookie" loginUrl="Login.aspx" protection="All" timeout="90" slidingExpiration="true"></forms>
</authentication>
<authorization>
  <deny users="?" />
</authorization>

Используя две из приведенных выше публикации x64igor и Phil Haselden, решили эту проблему:

1.x64igor привел пример для выполнения выхода из системы:

  • Сначала вам нужно Очистите файлы cookie аутентификации и сеансовые файлы cookie передавая обратно пустые файлы cookie в ответе на выход из системы.

    public ActionResult LogOff()
    {
        FormsAuthentication.SignOut();
        Session.Clear();  // This may not be needed -- but can't hurt
        Session.Abandon();
    
        // Clear authentication cookie
        HttpCookie rFormsCookie = new HttpCookie( FormsAuthentication.FormsCookieName, "" );
        rFormsCookie.Expires = DateTime.Now.AddYears( -1 );
        Response.Cookies.Add( rFormsCookie );
    
        // Clear session cookie 
        HttpCookie rSessionCookie = new HttpCookie( "ASP.NET_SessionId", "" );
        rSessionCookie.Expires = DateTime.Now.AddYears( -1 );
        Response.Cookies.Add( rSessionCookie );
    

2.Фил Хазельден привел приведенный выше пример того, как предотвратить кэширование после выхода из системы:

  • Тебе нужно Сделайте недействительным кэш на стороне клиента с помощью ответа.

        // Invalidate the Cache on the Client Side
        Response.Cache.SetCacheability( HttpCacheability.NoCache );
        Response.Cache.SetNoStore();
    
        // Redirect to the Home Page (that should be intercepted and redirected to the Login Page first)
        return RedirectToAction( "Index", "Home" ); 
    }
    

Ключевым моментом здесь является то, что вы говорите "Если я введу URL-адрес напрямую ...".

По умолчанию при проверке подлинности с помощью форм браузер кэширует страницы для пользователя. Поэтому, выбирая URL-адрес непосредственно из раскрывающегося списка адресов браузера или вводя его, МОЖЕТ получить страницу из кэша браузера и никогда не возвращаться на сервер для проверки аутентификации / авторизации. Решением этой проблемы является предотвращение кэширования на стороне клиента в событии Page_Load каждой страницы или в OnLoad () вашей базовой страницы:

Response.Cache.SetCacheability(HttpCacheability.NoCache);

Вы также можете позвонить:

Response.Cache.SetNoStore();

Я тоже с этим раньше боролся.

Вот аналогия с тем, что, похоже, происходит ... Новый посетитель, Джо, заходит на сайт и входит через страницу входа с помощью FormsAuthentication. ASP.NET генерирует новую личность для Джо и дает ему cookie. Это печенье похоже на ключ от дома, и пока Джо возвращается с этим ключом, он может открыть замок. Каждый посетитель получает новый ключ и новый замок для использования.

Когда вызывается FormsAuthentication.SignOut () , система сообщает Джо потерять ключ. Обычно это работает, поскольку у Джо больше нет ключа, он не может войти.

Однако, если Джо когда-нибудь вернется, а получил этот потерянный ключ, его снова впустят!

Из того, что я могу сказать, нет способа заставить ASP.NET изменить замок на двери!

Я могу жить с этим, вспоминая имя Джо в переменной Session. Когда он выходит из системы, я прекращаю сеанс, поэтому у меня больше нет его имени. Позже, чтобы проверить, разрешен ли ему вход, я просто сравниваю его Identity.Name с тем, что имеет текущий сеанс, и если они не совпадают, он не является действительным посетителем.

Короче говоря, для веб-сайта НЕ полагайтесь на User.Identity.IsAuthenticated , не проверяя также переменные сеанса!

Это работает для меня

public virtual ActionResult LogOff()
    {
        FormsAuthentication.SignOut();
        foreach (var cookie in Request.Cookies.AllKeys)
        {
            Request.Cookies.Remove(cookie);
        }
        foreach (var cookie in Response.Cookies.AllKeys)
        {
            Response.Cookies.Remove(cookie);
        }
        return RedirectToAction(MVC.Home.Index());
    }

После долгих поисков, наконец, это сработало для меня. Надеюсь, это поможет.

public ActionResult LogOff()
{
    AuthenticationManager.SignOut();
    HttpContext.User = new GenericPrincipal(new GenericIdentity(string.Empty), null);
    return RedirectToAction("Index", "Home");
}

<li class="page-scroll">@Html.ActionLink("Log off", "LogOff", "Account")</li>

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

Подтвердили ли вы, что доступ к страницам невозможен до того, как произойдет вход в систему?

Можете ли вы опубликовать используемые вами настройки web.config и код входа в систему?

Я писал базовый класс для всех своих Страниц и пришел к одной и той же проблеме.У меня был код, подобный следующему, и он не сработал.При трассировке управление переходит от оператора RedirectToLoginPage() к следующей строке без перенаправления.

if (_requiresAuthentication)
{
    if (!User.Identity.IsAuthenticated)
        FormsAuthentication.RedirectToLoginPage();

    // check authorization for restricted pages only
    if (_isRestrictedPage) AuthorizePageAndButtons();
}

Я выяснил, что есть два решения.Либо изменить проверку подлинности FormsAuthentication.RedirectToLoginPage();быть

if (!User.Identity.IsAuthenticated)
    Response.Redirect(FormsAuthentication.LoginUrl);

ИЛИ изменить web.config, добавив

<authorization>
  <deny users="?" />
</authorization>

Во втором случае, во время отслеживания, элемент управления не достиг запрошенной страницы.Он был немедленно перенаправлен на URL-адрес входа в систему до достижения точки останова.Следовательно, проблема не в методе SignOut(), а в методе перенаправления.

Я надеюсь, что это кому-нибудь поможет

С уважением

Я только что попробовал некоторые из предложенных здесь советов, и, хотя я смог использовать кнопку «Назад» в браузере, когда я щелкнул по выбору меню, токен [Authorize] для этого [ActionResult] отправил меня обратно на экран входа в систему.

Вот мой код выхода из системы:

        FormsAuthentication.SignOut();
        Response.Cookies.Remove(FormsAuthentication.FormsCookieName);
        Response.Cache.SetExpires(DateTime.Now.AddSeconds(-1));
        HttpCookie cookie = HttpContext.Request.Cookies[FormsAuthentication.FormsCookieName];
        if (cookie != null)
        {
            cookie.Expires = DateTime.Now.AddDays(-1);
            Response.Cookies.Add(cookie);
        }

Хотя функция возврата в браузере вернула меня назад и отобразила защищенное меню (я все еще над этим работаю), я не смог сделать ничего, что было защищено в приложении.

Надеюсь, это поможет

Я пробовал большинство ответов в этой теме, не повезло. Закончилось этим:

protected void btnLogout_Click(object sender, EventArgs e)
{
    FormsAuthentication.Initialize();
    var fat = new FormsAuthenticationTicket(1, "", DateTime.Now, DateTime.Now.AddMinutes(-30), false, string.Empty, FormsAuthentication.FormsCookiePath);
    Response.Cookies.Add(new HttpCookie(FormsAuthentication.FormsCookieName, FormsAuthentication.Encrypt(fat)));
    FormsAuthentication.RedirectToLoginPage();
}

Нашел его здесь: http://forums.asp.net/t/1306526. ASPX / 1

Этот ответ технически идентичен Хосро. Пакманеш. Я публикую его, чтобы уточнить, чем его ответ отличается от других ответов в этой теме, и в каком случае его можно использовать.

В общем, чтобы очистить пользовательский сеанс, делая

HttpContext.Session.Abandon();
FormsAuthentication.SignOut();

будет эффективно выходить из системы. Однако , если в том же запросе вам нужно проверить Request.isAuthenticated (как это часто бывает, например, в фильтре авторизации), то вы обнаружите, что

Request.isAuthenticated == true

даже после того, как вы сделали HttpContext.Session.Abandon () и FormsAuthentication.SignOut () .

Единственное, что сработало, это делал

AuthenticationManager.SignOut();
HttpContext.User = new GenericPrincipal(new GenericIdentity(string.Empty), null);

Это эффективно устанавливает Request.isAuthenticated = false .

Это начало происходить со мной, когда я установил аутентификацию > формы > Свойство пути в Web.config . Устранение, которое решило проблему, и простой FormsAuthentication.SignOut (); снова удалил cookie.

Возможно, вы входите из одного субдомена (sub1.domain.com) и затем пытаетесь выйти из другого субдомена (www.domain.com).

У меня была та же проблема, когда SignOut (), похоже, не смог правильно удалить тикет. Но только в конкретном случае, когда какая-то другая логика вызвала перенаправление. После того как я удалил этот второй редирект (заменил его сообщением об ошибке), проблема исчезла.

Проблема, возможно, заключалась в том, что страница перенаправлялась не в то время, поэтому не запускалась аутентификация.

У меня сейчас похожая проблема, и я считаю, что проблема в моем случае, так же как и в оригинальном постере, связана с перенаправлением. По умолчанию Response.Redirect вызывает исключение, которое сразу всплывает, пока не будет перехвачено, и перенаправление немедленно выполнено, я предполагаю, что это предотвращает передачу измененной коллекции файлов cookie клиенту. Если вы измените свой код для использования:

Response.Redirect("url", false);

Это предотвращает исключение и, по-видимому, позволяет правильно отправлять cookie клиенту.

Просто попробуйте отправить переменную сеанса, когда вы нажимаете войти. И на странице приветствия сначала проверьте, пуст ли этот сеанс, как это, при загрузке страницы или в событии Init:

if(Session["UserID"] == null || Session["UserID"] == "")
{
    Response.Redirect("Login.aspx");
}

Для меня работает следующий подход. Я думаю, есть ли какая-либо ошибка после " FormsAuthentication.SignOut () " Заявление, SingOut не работает.

public ActionResult SignOut()
    {
        if (Request.IsAuthenticated)
        {
            FormsAuthentication.SignOut();

            return Redirect("~/");
        }
        return View();
     }

Вы тестируете / видите это поведение с помощью IE? Возможно, что IE обслуживает эти страницы из кэша. Общеизвестно, что IE трудно очистить кэш, и во многих случаях, даже после выхода из системы, введите URL-адрес одного из «защищенных» ключей. на страницах будет отображаться кэшированное содержимое ранее.

(Я видел такое поведение, даже когда вы входите в систему как другой пользователь, и IE отображает панель " Welcome " в верхней части страницы со старым именем пользователя. В настоящее время обычно перезагрузка обновляет его , но если он постоянен, это может быть проблемой кеширования.)

Выполнение Session.abandon () и уничтожение файла cookie работает довольно хорошо. Я использую mvc3, и похоже, что проблема возникает, если вы заходите на защищенную страницу, выходите из системы и просматриваете историю браузера. Ничего страшного, но все равно немного раздражает.

Попытка просмотреть ссылки в моем веб-приложении работает правильно.

Возможно, стоит отключить кэширование в браузере.

Для MVC это работает для меня:

        public ActionResult LogOff()
        {
            FormsAuthentication.SignOut();
            return Redirect(FormsAuthentication.GetRedirectUrl(User.Identity.Name, true));
        }

Я хотел добавить некоторую информацию, чтобы помочь понять проблему. Проверка подлинности с помощью форм позволяет хранить пользовательские данные либо в файле cookie, либо в строке запроса URL-адреса. Метод, поддерживаемый вашим сайтом, можно настроить в файле web.config.

в соответствии в Microsoft :

  

Метод SignOut удаляет информацию о билете проверки подлинности с помощью форм   из файла cookie или URL-адреса , если CookiesSupported имеет значение false .

В то же время они говорят :

  

Одно из значений HttpCookieMode, которое указывает, является ли   Приложение настроено для проверки подлинности без файлов cookie. <Сильный> Элемент    по умолчанию - UseDeviceProfile .

Наконец, что касается UseDeviceProfile, они говорят :

  

Если для свойства CookieMode установлено значение UseDeviceProfile,    CookiesSupported возвращает true, если браузер для    текущий запрос поддерживает файлы cookie и перенаправление с помощью файлов cookie ;   в противном случае свойство CookiesSupported вернет false.

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

Один из способов заставить SignOut работать самостоятельно - изменить режим файлов cookie на «UseCookies». (т. е. требуются файлы cookie) в файле web.config:

<authentication mode="Forms">
  <forms loginUrl="~/Account/SignIn" cookieless="UseCookies"/>
</authentication>

Согласно моим тестам, это делает SignOut работающим само по себе за счет вашего сайта, теперь требующего, чтобы куки функционировали должным образом.

Помните, что WIF отказывается сообщать браузеру о необходимости очистки файлов cookie, если сообщение wsignoutcleanup из STS не соответствует URL-адресу с именем приложения из IIS, и я имею в виду ДЕЛО ЧУВСТВИТЕЛЬНО . WIF отвечает зеленой проверкой OK, но не отправит команду на удаление файлов cookie в браузер.

Итак, вам нужно обратить внимание на чувствительность к регистру ваших URL.

Например, ThinkTecture Identity Server сохраняет URL-адреса посещающих RP в одном файле cookie, но делает их все строчными. WIF получит сообщение wsignoutcleanup в нижнем регистре и сравнит его с именем приложения в IIS. Если он не совпадает, он не удаляет куки, но сообщит браузеру «ОК». Итак, для этого Identity Server мне нужно было написать все URL-адреса в web.config и имена всех приложений в IIS в нижнем регистре, чтобы избежать таких проблем.

Также не забудьте разрешить сторонние файлы cookie в браузере, если у вас есть приложения вне поддоменов STS, иначе браузер не удалит файлы cookie, даже если WIF скажет ему об этом.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top