Ответ 1
Я придумал довольно устрашающее решение. То, что я реализовал, - это когда пользователь "Боб" входит в систему со своего ПК, а затем тот же пользователь "Боб" входит в систему из другого места, вход в систему из первого места (их ПК) будет убит, а второй войдите в систему, чтобы жить. Как только пользователь входит в систему, он вставляет запись в пользовательскую таблицу, созданную мной под названием "Логины". При успешном входе в эту таблицу будет вставлена одна запись со значениями для "UserId, SessionId и LoggedIn". UserId довольно понятен, SessionId - это текущий идентификатор сеанса (объясняется ниже, как получить), а LoggedIn - это просто логическое значение, которое изначально установлено на True при успешном входе в систему. Я помещаю эту логику "вставки" в мой метод входа в свой AccountController после успешной проверки пользователя: см. Ниже:
Logins login = new Logins();
login.UserId = model.UserName;
login.SessionId = System.Web.HttpContext.Current.Session.SessionID;;
login.LoggedIn = true;
LoginsRepository repo = new LoginsRepository();
repo.InsertOrUpdate(login);
repo.Save();
В моей ситуации я хочу поместить чек на каждом из моих контроллеров, чтобы узнать, зарегистрирован ли текущий зарегистрированный пользователь в другом месте, и если это так, убейте другие сеансы. Затем, когда убитый сеанс пытается перемещаться в любом месте, я разместил эти проверки, он выйдет из системы и перенаправит их на экран входа в систему.
У меня есть три основных метода, которые выполняют эти проверки:
IsYourLoginStillTrue(UserId, SessionId);
IsUserLoggedOnElsewhere(UserId, SessionId);
LogEveryoneElseOut(UserId, SessionId);
Сохранить идентификатор сеанса для сеанса [ "..." ]
Прежде всего, я сохраняю SessionID в коллекции Session внутри AccountController, внутри метода Login
([HttpPost]
):
if (Membership.ValidateUser(model.UserName, model.Password))
{
Session["sessionid"] = System.Web.HttpContext.Current.Session.SessionID;
...
Код контроллера
Затем я помещаю логику внутри своих контроллеров для управления потоком выполнения этих трех методов. Обратите внимание, что если по какой-либо причине Session["sessionid"]
есть null
, он просто просто присвоит ей значение "empty". Это на случай, если по какой-то причине оно возвращается как null:
public ActionResult Index()
{
if (Session["sessionid"] == null)
Session["sessionid"] = "empty";
// check to see if your ID in the Logins table has LoggedIn = true - if so, continue, otherwise, redirect to Login page.
if (OperationContext.IsYourLoginStillTrue(System.Web.HttpContext.Current.User.Identity.Name, Session["sessionid"].ToString()))
{
// check to see if your user ID is being used elsewhere under a different session ID
if (!OperationContext.IsUserLoggedOnElsewhere(System.Web.HttpContext.Current.User.Identity.Name, Session["sessionid"].ToString()))
{
return View();
}
else
{
// if it is being used elsewhere, update all their Logins records to LoggedIn = false, except for your session ID
OperationContext.LogEveryoneElseOut(System.Web.HttpContext.Current.User.Identity.Name, Session["sessionid"].ToString());
return View();
}
}
else
{
FormsAuthentication.SignOut();
return RedirectToAction("Login", "Account");
}
}
Три метода
Вот те методы, которые я использую для проверки того, что вы все еще вошли в систему (т.е. убедитесь, что вы не были вызваны другой попыткой входа в систему), и если да, проверьте, зарегистрирован ли ваш идентификатор пользователя в другом месте, и если это так, отбросьте их, просто установив их статус LoggedIn в false
в таблице Logins.
public static bool IsYourLoginStillTrue(string userId, string sid)
{
CapWorxQuikCapContext context = new CapWorxQuikCapContext();
IEnumerable<Logins> logins = (from i in context.Logins
where i.LoggedIn == true && i.UserId == userId && i.SessionId == sid
select i).AsEnumerable();
return logins.Any();
}
public static bool IsUserLoggedOnElsewhere(string userId, string sid)
{
CapWorxQuikCapContext context = new CapWorxQuikCapContext();
IEnumerable<Logins> logins = (from i in context.Logins
where i.LoggedIn == true && i.UserId == userId && i.SessionId != sid
select i).AsEnumerable();
return logins.Any();
}
public static void LogEveryoneElseOut(string userId, string sid)
{
CapWorxQuikCapContext context = new CapWorxQuikCapContext();
IEnumerable<Logins> logins = (from i in context.Logins
where i.LoggedIn == true && i.UserId == userId && i.SessionId != sid // need to filter by user ID
select i).AsEnumerable();
foreach (Logins item in logins)
{
item.LoggedIn = false;
}
context.SaveChanges();
}
EDIT Я просто хочу добавить, что этот код игнорирует возможности функции "Запомнить меня". Мое требование не связано с этой функцией (на самом деле, мой клиент не хотел использовать его по соображениям безопасности), поэтому я просто его не выпускал. Однако с некоторым дополнительным кодированием я вполне уверен, что это можно было бы принять во внимание.