На сайте asp.net как предотвратить множественные логины одного и того же идентификатора пользователя?
Просьба указать, как предотвратить одновременное вход в систему нескольких пользователей с использованием идентификатора пользователя?
Я искал в Интернете и нашел некоторые способы, но почему-то они не работают в таких ситуациях:
- Если javascript в браузере отключен.
- Если пользователь не нажимает выйти и напрямую закрывает браузер.
Пожалуйста, предложите мне какой-то способ.
спасибо
haansi
Ответы
Ответ 1
Там может быть несколько возможностей. Быстрый ответ:
-
Поддерживать флаг в базе данных; при каждом обновлении флажка. Например, при каждом запросе проверки подлинности вы можете отклонить запрос на вход, если флаг уже прав.
-
Кроме того, вы можете сохранить список пользователей в объекте Application
и использовать .Contains
, чтобы узнать, существует ли он.
- EDIT -
Давайте попробуем параметр флага базы данных; и предположим, что у вас есть метод под названием StillLoggedIn(User)
, который обновляет дату/время и флаг.
Итак, когда пользователь входит в систему:
- Приложение будет аутентифицировать пользователя и установить флаг = 1 и пометить отметку даты/времени.
-
Для последующих запросов приложение вызывает StillLoggedIn(User)
;
-
Подготовьте службу Windows, которая время от времени будет просматривать базу данных (скажем, через 5 минут, если у вас есть 10000 пользователей). Служба будет сравнивать дату/время базы данных с текущей датой/временем и пометить флаг как 0
, если currentTime минус lastUsedTime больше, скажем, 5 минут.
Это может быть что угодно, кроме базы данных и службы Windows.
Ответ 2
Мы реализовали систему для этого в следующих строках:
- Добавлено свойство профиля пользователей для хранения идентификатора сеанса.
- Всякий раз, когда пользователь входит в систему, сохраните свой идентификатор сеанса в профиле.
- На любой странице, требующей такого уровня безопасности, проверьте, соответствует ли идентификатор сеанса, сохраненный в профиле, их сеансу. Эта проверка может быть выполнена в пользовательском обработчике событий AuthorizeRequest или может выполняться в базовом классе, из которого эти страницы происходят, а если нет, перенаправлять их на страницу входа.
Мы пошли для опции базового класса, поскольку у нас есть два уровня аутентификации:
- У пользователя есть маркер файла cookie, чтобы доказать, что они входили в систему в какой-то момент в прошлом - это прекрасно для отображения ограниченного содержимого сайта.
- Пользователь фактически предоставил свои данные для входа в этот сеанс - это необходимо, когда вы показываете им какие-либо личные данные (адреса электронной почты, предпочтения, сохраненные поиски работы и т.д.).
Основные проблемы, которые вы найдете практически в любой системе:
- Использование IP-адреса пользователей является ненадежным - корпоративные пользователи, те, кто находится за прокси-серверами, и т.д., часто используют IP-адрес, поэтому он будет отображаться как один и тот же пользователь.
- Полагая, что пользователь выходит из системы, ненадежен - компьютер/браузер пользователей может потерпеть крах, не предоставив им возможность выйти из системы, пользователь может/забудет выйти из системы.
- Опора на тайм-ауты сеанса ненадежна - если вы не используете сеансы
InProc
, событие SessionEnd никогда не срабатывает, если ваш сервер выходит из строя, событие не вызывается и т.д.
Проблемы, которые вы найдете с таким решением, как мои:
- Он не останавливает вход второго пользователя - вместо этого он блокирует первого пользователя, что должно препятствовать совместному использованию деталей.
- Если вы не реализуете это как обработчик AuthorizeRequest, вы должны помнить, что выполняете проверку на страницах, которые следует заблокировать.
Ответ на комментарий
В ответ на ваши конкретные запросы:
- поставщик профилей по умолчанию сохраняет данные в той же базе данных SQL, что и поставщик членства (таблицы создаются вместе с членством и ролями таблицы). Если вы должны были хранить его "в кеше", это должен быть глобальный кэш приложений по строкам KMan предлагает в варианте 2 - и, как указано в комментариях, вам нужно будет построить тайм-аут для этого, и это вернет к вопросу о достоверном определении этого.
- Пользователь не выходит из системы: он обрабатывается в нашей системе, не блокируя будущих пользователей, а блокируя ранее зарегистрированных пользователей - так:
- Алиса приходит на сайт, входит в систему, начинает просмотр.
- Боб приходит на сайт и входит в систему с деталями Алисы, начинает просмотр.
- Алиса пытается продолжить просмотр, заблокирована, ей нужно снова войти в систему.
- Боб теперь заблокирован.
- и др.
В самом основном, это не остановит пользователей, разделяющих их логины, но вызовет их раздражение, заставив их продолжать вход в систему. Если вам нужно добавить задержку в процесс входа в систему, то, если другой session id пытается войти в сайт в течение таймаута сеанса (по умолчанию 20 минут) или в другое время, например, на основании среднего времени, которое пользователь проводит на странице, а затем отклоняет попытку входа.
Ответ 3
Здесь нет ни одного ответа, поскольку это зависит от того, как вы аутентифицируете пользователей. Однако основная логика была бы простой: когда пользователь входит в систему, проверяет свое имя пользователя или идентификатор на список уже зарегистрированных пользователей и, если есть совпадение, не аутентифицирует их (и вместо этого дает им какое-то сообщение, объясняющее почему они не могут войти в систему).
Очевидно, что именно то, как вы это делаете, зависит от того, как вы аутентифицируете пользователей и сохраняете данные пользователя - вам нужно будет предоставить более подробную информацию, если вам нужна дополнительная помощь.
Ответ 4
Я просмотрел таблицу членства и не видел ни одного столбца, такого как "IsLoggedIn", поэтому членский API не отвечает этому требованию.
Возможно, вы можете использовать систему кэша Asp.net и указать пользователя как "LoggedIn". Таким образом, вы можете проверить дополнительные логины.
Ответ 5
Так я и делаю.
После входа в систему, проверьте флаг и идентификатор сеанса от БД, если вы вошли в систему с той же учетной записью и другим идентификатором sessionID (Сравните недавно сгенерированный текущий идентификатор сеанса и идентификатор сеанса от БД), предупредите пользователя о том, что "система обнаружила, что вы не вышли из системы ваш последний логин, нажмите <" OK " > , чтобы выйти из последнего входа и создать новый сеанс."
Если ОК, просто замените старый SessionId текущим SessionID в DB.
Еще одна вещь - проверить текущие идентификаторы sessionID и sessionID из БД на каждой странице, если это не так, выйти и перенаправить на страницу входа.
Независимо от того, что пользователь не вышел из системы правильно или просто закрыл браузер, у пользователя есть шанс выйти из системы и не нужно ждать окончания сеанса от IIS.
Это предотвратит одновременное использование нескольких учетных записей с одинаковой учетной записью.
Надеюсь на эту помощь, спасибо...
Ответ 6
Что мы сделали, мы использовали комбинацию состояния сеанса и состояния приложения для предотвращения повторного входа в систему.
Когда пользователь регистрирует свой userId, он извлекается из базы данных членства asp.net и сохраняется в состоянии приложения как уникальный объект.
Так как состояние приложения является глобальным для приложения и не является специфичным для пользовательского сеанса, мы можем проверить, сохранен ли userId в состоянии приложения. Если он уже сохранен, мы можем уведомить пользователя и остановить вход в систему.
Когда сеанс истекает (в Session_End в файле Global.asax), этот объект состояния приложения для этого конкретного пользователя может быть удален из состояния приложения, чтобы он мог снова войти в систему после истечения срока его сессии.
Здесь код:
В Login.aspx.cs:
protected void OnLoggingIn(object sender, LoginCancelEventArgs e)
{
// Accesses the database to get the logged-in user.
MembershipUser userInfo = Membership.GetUser(LoginUser.UserName);
UserMan.UserID = userInfo.ProviderUserKey.ToString();
if (Application[UserMan.UserID] != null)
{
if (Convert.ToString(Application[UserMan.UserID]) == UserMan.UserID)
{
e.Cancel = true;
}
else
{
// Save the user id retrieved from membership database to application state.
Application[UserMan.UserID] = UserMan.UserID;
}
}
else
{
Application[UserMan.UserID] = UserMan.UserID;
}
}
И в Global.asax:
void Session_End(object sender, EventArgs e)
{
// Code that runs when a session ends.
// Note: The Session_End event is raised only when the sessionstate mode
// is set to InProc in the Web.config file. If session mode is set to StateServer
// or SQLServer, the event is not raised.
if (Application[UserMan.UserID] != null)
{
if (Convert.ToString(Application[UserMan.UserID]) == UserMan.UserID)
{
Application.Contents.Remove(UserMan.UserID);
}
}
}
Несмотря на то, что это решение кажется немного беспорядочным, оно работает достаточно хорошо, не слишком много кодирования и меньше ударов базы данных.
Ответ 7
Zhaph - Ben Duguid, Небольшой заметки Профиль не может быть доступен в AuthenticateRequest, поскольку он не создан до события приложения AcquireSessionState, поэтому, если бы они использовали такой подход (вместо подхода к странице), им пришлось бы обрабатывать AcquireRequestState или PostAcquireRequestState
Ответ 8
Когда член входа в систему. setup a Random int ex. randNo, сохранить кеш [UserName] = randNo, session [UserName] = randNo.
Когда участник получает доступ к любой странице, мы проверяем: cache [UserName] == Session [UserName] в порядке, иначе этот пользователь будет выходить из системы.
(Среднее: сначала вход, выход из системы)