There are several sites there that prevent multiple logins, It only allows a single device for the same id so to do the same I have created a simple solution to solve this situation in C#. For example, we have a site that provides some kind of service based on subscription, if we allow multiple logins for multiple devices, in that case, we have lost because a single user shares his/her id with others so all can use the same service without payment. To prevent that case below solution works.
Here I implement one helper class, ActionFilterAttribute, and LoginHistory table to maintain the logins history of users.
LoginHistory.cs (SQL Table)
public class LoginHistory { [Key] public int ID { get; set; } public string UserId { get; set; } public string SessionId { get; set; } public bool LoggedIn { get; set; } }
HelperExtention.cs
public class HelperExtention { public static bool IsUserLoginStillTrue(string userId, string sessionId) { ApplicationDbContext context = new ApplicationDbContext(); IEnumerable<LoginHistory> logins = (from i in context.LoginHistory where i.LoggedIn == true && i.UserId == userId && i.SessionId == sessionId select i).AsEnumerable(); return logins.Any(); } public static bool IsUserLoggedOnElsewhere(string userId, string sessionId) { ApplicationDbContext context = new ApplicationDbContext(); IEnumerable<LoginHistory> logins = (from i in context.LoginHistory where i.LoggedIn == true && i.UserId == userId && i.SessionId != sessionId select i).AsEnumerable(); return logins.Any(); } public static void LogOutRestUsersForSameUserId(string userId, string sessionId) { ApplicationDbContext context = new ApplicationDbContext(); var logins = (from i in context.LoginHistory where i.LoggedIn == true && i.UserId == userId && i.SessionId != sessionId select i).ToList(); foreach (LoginHistory item in logins) { item.LoggedIn = false; } context.SaveChanges(); } }
GlobalActionFilterAttribute.cs
This method will be called the byASP.NET MVC framework before any action method executes.
public class GlobalActionFilterAttribute : ActionFilterAttribute { public override void OnActionExecuted(ActionExecutedContext filterContext) { } public override void OnActionExecuting(ActionExecutingContext filterContext) { var userID = HttpContext.Current.User.Identity.GetUserId(); if (filterContext.HttpContext.Session["sessionid"] != null) { if (HelperExtention.IsUserLoginStillTrue (userID, filterContext.HttpContext.Session["sessionid"].ToString())) { if (!HelperExtention.IsUserLoggedOnElsewhere (userID, filterContext.HttpContext.Session["sessionid"].ToString())) { } else { HelperExtention.LogOutRestUsersForSameUserId (userID, filterContext.HttpContext.Session["sessionid"].ToString()); } } else { filterContext.HttpContext.Session.Abandon(); AuthenticationManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie); filterContext.Result = new RedirectResult("/Account/Login"); } } else { filterContext.HttpContext.Session.Abandon(); AuthenticationManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie); filterContext.Result = new RedirectResult("/Account/Login"); } } private IAuthenticationManager AuthenticationManager { get { return HttpContext.Current.GetOwinContext().Authentication; } } }
Below is the controller code you can use as per requirements. I used an Identity server to authenticate but you can use a simple controller and logic also. The below method will just check the user is valid or not and if it’s valid it will insert login history in the LoginHistory table.
[HttpPost] [AllowAnonymous] [ValidateAntiForgeryToken] public async Task<ActionResult> Login(LoginViewModel model, string returnUrl) { if (!ModelState.IsValid) { return View(model); } // This doesn't count login failures towards account lockout // To enable password failures to trigger account lockout, change to shouldLockout: true var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: false); switch (result) { case SignInStatus.Success: { var sessionID = System.Web.HttpContext.Current.Session.SessionID; var userID = SignInManager.AuthenticationManager.AuthenticationResponseGrant.Identity.GetUserId(); Session["sessionid"] = sessionID; LoginHistory history = new LoginHistory { UserId = userID, SessionId = sessionID, LoggedIn = true }; if (!_db.LoginHistory.Any(x => x.SessionId.Equals(sessionID) && x.UserId.Equals(userID))) { _db.LoginHistory.Add(history); await _db.SaveChangesAsync(); } else { var oldHistory = _db.LoginHistory.FirstOrDefault(x => x.SessionId.Equals(sessionID) && x.UserId.Equals(userID)); if (oldHistory != null) { oldHistory.LoggedIn = true; _db.SaveChanges(); } } return RedirectToLocal(returnUrl); } case SignInStatus.LockedOut: return View("Lockout"); case SignInStatus.RequiresVerification: return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = model.RememberMe }); case SignInStatus.Failure: default: ModelState.AddModelError("", "Invalid login attempt."); return View(model); } }
You can also write the below lines on registration if you want.
var sessionID = System.Web.HttpContext.Current.Session.SessionID; Session["sessionid"] = sessionID;
That’s it this works for me, you can use a piece of code or modify code as per your requirements.
hope you guys found something useful. Please give your valuable feedback/comments/questions about this article. Please let me know how you like and understand this article and how I could improve it. If you like this blog you can buy me Pizza.
In this article, we have to show Create and Used PIPE in angular
In this article, we have to show Create and Used PIPE in angular
In this article, we have to show Create and Used PIPE in angular