Drop user authenticated in ASP.NET MVC - c#

I have a web system developed with ASP.NET MVC 4.
We have a user management that allows users to edit/delete other users.
On delete function, currently i'm doing only a delete on database.
So here is my login controller/method:
[HttpPost]
public ActionResult Login(LoginViewModel loginViewModel)
{
if (_loginService == null)
_loginService = new LoginService();
var result = _loginService.Login(loginViewModel.User, loginViewModel.Password);
if (!result.Error)
{
var userData = JsonConvert.SerializeObject(result.User);
FormsAuthentication.SetAuthCookie(result.User.Id, false);
var ticket = new FormsAuthenticationTicket(1, result.Id, DateTime.Now, DateTime.Now.AddMinutes(9999), true, userData, FormsAuthentication.FormsCookiePath);
var encryptedCookie = FormsAuthentication.Encrypt(ticket);
var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedCookie) { Expires = DateTime.Now.AddHours(14) };
Response.Cookies.Add(cookie);
}
return new JsonResult
{
Data = result
};
}
And I treat that return on client side with some javascript. This is working fine by now.
For every Controller that user must be authenticated, I have [Authorize] attribute.
Lets say that I just logged in with user ABC. As long as ABC cookie is alive he can navigate fine.. the problem is when some user (lets say ZXC) deletes user ABC, he will still navigate fine until the cookie expires.
Is there a way to drop ABC session on IIS in the moment ZXC deletes him from database?
I don't know.. force a cookie expire. I just don't wanna implement a consult for each action done in navigation to check if the user is still "alive" in database.
Any ideas, suggestions?

Firstly, no. There is no way to access cookies in another session as they only exist for the lifetime of the request/response. However, you could store a static List of all current authenticated users and invalidate them that way.
This is a bit problematic because in the case that the App Pool recycles - all users will be 'logged out'. If this is not an issue for you (i.e. the app pool recycles at 2am and it is for a business system that does not operate at 2 am) then you can try this...
Code provided is untested
source: https://msdn.microsoft.com/en-us/library/system.web.security.formsauthenticationmodule.authenticate
EDIT:
I was not removing the cookie from the request and expiring it in the response.
In the Global.asax
private static List<string> _authenticatedUsers = new List<string>();
public static AuthenticateUser (MyApplicationUser user)
{
if(!_authenticatedUsers.ContainsKey(user.Username))
{
_authenticatedUsers.Add(user.Username);
}
}
public static DeauthenticateUser (MyApplicationUser user)
{
if(_authenticatedUsers.ContainsKey(user.Username))
{
_authenticatedUsers.Remove(user.Username);
}
}
public void FormsAuthentication_OnAuthenticate(object sender, FormsAuthenticationEventArgs args)
{
if (FormsAuthentication.CookiesSupported)
{
if (Request.Cookies[FormsAuthentication.FormsCookieName] != null)
{
try
{
FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(
Request.Cookies[FormsAuthentication.FormsCookieName].Value);
MyApplicationUser user = JsonConvert.DeserializeObject(ticket.UserData);
if(user == null || !_authenticatedUsers.Any(u => u == user.Username))
{
// this invalidates the user
args.User = null;
Request.Cookies.Remove(FormsAuthentication.FormsCookieName);
HttpCookie myCookie = new HttpCookie(FormsAuthentication.FormsCookieName);
DateTime now = DateTime.Now;
myCookie.Value = "a";
myCookie.Expires = now.AddHours(-1);
Response.Cookies.Add(myCookie);
Response.Redirect(FormsAuthentication.LoginUrl);
Resonpse.End();
}
}
catch (Exception e)
{
// Decrypt method failed.
// this invalidates the user
args.User = null;
Request.Cookies.Remove(FormsAuthentication.FormsCookieName);
HttpCookie myCookie = new HttpCookie(FormsAuthentication.FormsCookieName);
DateTime now = DateTime.Now;
myCookie.Value = "a";
myCookie.Expires = now.AddHours(-1);
Response.Cookies.Add(myCookie);
Response.Redirect(FormsAuthentication.LoginUrl);
Resonpse.End();
}
}
}
else
{
throw new HttpException("Cookieless Forms Authentication is not " +
"supported for this application.");
}
}
In your login action
public ActionResult Login(LoginViewModel loginViewModel)
{
...
if (!result.Error)
{
...
MvcApplication.AuthenticateUser(result.User);
...
}
...
}
In your logout action
public ActionResult Logout(...)
{
...
MvcApplication.DeauthenticateUser(user);
...
}
In your delete method
...
MvcApplication.DeauthenticateUser(user);
...

Related

Redirect logged in user to new website with automatic authentication

I have one website designed in ASP.NET MVC 5 hosted with website name of www.oldsite.com.
We just now started a new website - www.newsite.com with some changes to the ASP.NET MVC code and but database is the same for both sites.
When a user logs in to the old website, www.oldsite.com verifies the login details (userid and password) and after successful login redirects the user based on some condition to new website www.newsite.com with automatic login (user does not need to re-enter userid and password in login page again on www.newsite.com) and shows the home page of www.newsite.com.
This is my code
int timeout = login.RememberMe ? 600 : 60; // 525600 min = 1 year
var ticket = new FormsAuthenticationTicket(v.PEmailId, login.RememberMe, timeout);
string encrypted = FormsAuthentication.Encrypt(ticket);
var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encrypted);
cookie.Expires = DateTime.Now.AddMinutes(timeout);
cookie.HttpOnly = true;
Response.Cookies.Add(cookie);
if (some condition)
{
return Redirect("www.newsite.com");
}
I need some login authentication cookies code, I am using ASP.NET identity.
Please tell me how to redirect from old site to new site www.newsite.com with login credentials (give like userid and password parameter in login page and automatically login into new website) or how to create cookies for new website www.newsite.com for automatic login without entering userid and password.
Thank you
From old site you can pass the username and password as parameter.
return Redirect(string.Format("https://newsite.com/Home/Index?username={0}&password={1}","username", "password"));
In new site create a function that allow anonymous users. Then validate the user credential. If the user is valid one then add cookies and redirect to the page you want.
[AllowAnonymous]
public class HomeController : Controller
{
public ActionResult Index(string username, string password)
{
// validate the user credential
// add cookie
User user = new User();
user.UserName = username;
user.Password = password;
AddCookie(user);
return RedirectToAction("Index", "Dashboard");
}
public void AddCookie(User user)
{
string encryptTicket, userData;
HttpCookie httpCookie = null;
try
{
userData = JsonConvert.SerializeObject(user);
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(
1, user.UserName, DateTime.Now, DateTime.Now.AddHours(1), true, userData, FormsAuthentication.FormsCookiePath);
encryptTicket = FormsAuthentication.Encrypt(ticket);
httpCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptTicket);
Response.Cookies.Add(httpCookie);
}
catch (Exception exception)
{
}
return httpCookie;
}
}
public class User
{
public string UserName { get; set; }
public string Password { get; set; }
}

C# MVC 5 The ticket cookie is cleared when the form authentication signs out

I need to access the cookies to get the user and password and then set them in the text boxes of the Login view because in that view is checked "Remember me".
LogOff method
public ActionResult LogOff()
{
//Session.Abandon();
// sign out.
FormsAuthentication.SignOut();
return RedirectToAction("Index", "Login");
}
Initialization of sessions and cookies after a successful login.
private void InitializeSessionVariables(AgentDTO user)
{
// SessionModel.AgentId = user.ID;
Response.Cookies.Clear();
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1,user.MobilePhone,DateTime.Now,DateTime.Now.AddDays(30),true,"",FormsAuthentication.FormsCookiePath);
// Encrypt the ticket.
string encryptedTicket = FormsAuthentication.Encrypt(ticket);
// Create the cookie.
HttpCookie authenticationCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket); // Name of auth cookie (it's the name specified in web.config) // Hashed ticket
authenticationCookie.Expires = DateTime.Now.AddDays(365);
// Add the cookie to the list for outbound response
Response.Cookies.Add(authenticationCookie);
}
Action Result of Login View
I have problem when I first log out and then try to access the cookie but it returns null because I run "FormsAuthentication.SignOut ();"
public ActionResult Index(LogonDTO model, string message = null, string reason = null)
{
if (SessionModel.AgentMobilePhone != null) return RedirectToAction("Index", "Home");
if (reason != null) message = "Su sessiĆ³n ha expirado. Vuelva a loguearse.";
ViewBag.Message = message;
if (Request.Cookies[FormsAuthentication.FormsCookieName] != null)
{
HttpCookie authCookie = Request.Cookies[FormsAuthentication.FormsCookieName];
FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value);
model.Username = authTicket.Name;
//model.Password = "in progress..."
}
return View(model);
}
You can use javascript to store User information if he click on Remember Me checkbox
use
localStorage.setItem("UserName", "Smith");
to set values
and on Login page on document ready event of Jquery write below code
var UserName = localStorage.getItem("UserName");
if (UserName) $("#username").val(UserName);
Hope this will solve your problem.

SetPrincipal (#User.Identity.Name) from a cookie in ASP.Net MVC

I like to know how I can set the #User.Identity.Name via a cookie when a user clicks on a remember me checkbox.
Cookie code
if (_model.RememberMe)
{
HttpCookie cookie = new HttpCookie("login");
cookie.Values.Add("username", _model.Username);
cookie.Expires = DateTime.Now.AddDays(30);
Response.Cookies.Add(cookie);
}
First login code
if (Membership.ValidateUser(Username,Password))
{
RememberMe();
FormsAuthentication.RedirectFromLoginPage(Username, false);
}
On the first login the Identity.name is set but when I close the browser and go back on to the site. it logs in correctly without the user putting in their credentials but the Identity.name is empty.
if (Request.Cookies["login"] != null)
{
// We know the automatic log in has worked as it comes into here...
}
What do I need to do once the user by passes the login page so I can setup the iPrincipal object?
Thanks
Try below code please
Note : please check it on page view not in the same method on creation of cokies
private void CreateCokies(string userName)
{
var authTicket = new FormsAuthenticationTicket(1, userName, DateTime.Now, DateTime.Now.AddMinutes(30), true, userName);
string cookieContents = FormsAuthentication.Encrypt(authTicket);
var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, cookieContents)
{
Expires = authTicket.Expiration,
Path = FormsAuthentication.FormsCookiePath
};
Response.Cookies.Add(cookie);
}

MVC Forms Authentication and Session, Authorize Issues

I have a MVC project that I'm using Forms Authentication, and I had to implement Roles for certain pages, so I got this in global.asax:
protected void Application_AuthenticateRequest(Object sender, EventArgs e)
{
HttpCookie authCookie = Context.Request.Cookies[FormsAuthentication.FormsCookieName];
if (authCookie == null || authCookie.Value == "")
{
return;
}
FormsAuthenticationTicket authTicket;
try
{
authTicket = FormsAuthentication.Decrypt(authCookie.Value);
}
catch
{
return;
}
string[] roles = authTicket.UserData.Split(';');
if (Context.User != null)
{
Context.User = new GenericPrincipal(Context.User.Identity, roles);
}
}
And I save the user roles when I log in my model:
//After checking login/password
HttpCookie cookie = HttpContext.Current.Request.Cookies.Get(FormsAuthentication.FormsCookieName);
if (cookie == null)
{
cookie = new HttpCookie(FormsAuthentication.FormsCookieName);
HttpContext.Current.Response.Cookies.Add(cookie);
}
string userRoles = null;
if (users[i].PerfilID == UserRanks.Admin)
{
userRoles = "Admin;Users";
}
else
{
userRoles = "Users";
}
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(0,
users[i].Name,
DateTime.Now,
DateTime.Now.AddDays(1),
false,
userRoles,
FormsAuthentication.FormsCookiePath
);
cookie.Value = FormsAuthentication.Encrypt(ticket);
HttpContext.Current.Response.Cookies.Set(cookie);
HttpContext.Current.Session["UserID"] = users[i].UserID;
HttpContext.Current.Session["LastLogin"] = users[i].LastLogin;
HttpContext.Current.User = new GenericPrincipal(HttpContext.Current.User.Identity, userRoles.Split(';'));
To retrieve the values of the session variables, I have a static property:
public static int UserID
{
get
{
object sessionData = HttpContext.Current.Session["UserID"];
if (sessionData == null)
{
//I had something here...
return 0;
}
return Convert.ToInt32(sessionData);
}
private set { }
}
Before I implemented roles authorization, I used to save the UserID in the cookie userData, and if the UserID in the session, when requested, was null, I'd retrieve it from the cookie instead (and set it to the session again).
Now the userData is being used to the roles management and I'm having issues with the session dropping faster than the cookie expiration, and I have users logged in which I can't retrieve their UserIDs and thus fails for all operations.
So I have to put a checker in each controller function such as:
if (MyUser.Session.UserID == 0)
{
//redirect to Login
}
...which defeats the whole purpose of using [Authorize] I guess.
Is there a better way to handle login expiration and session variables like this?
I thought about using JSON or some other format and save a bunch of userData in the cookie, but I'd like something simpler, if possible.
Also, I'm doing this in the login:
HttpContext.Current.User = new GenericPrincipal(HttpContext.Current.User.Identity, userRoles.Split(';'));
Which seems to be about the same the AuthenticateRequest does (I got that part from elsewhere, seemed to be the recommended way to handle member roles), but it doesn't work like it should. The user always gets redirected out on the [Authorize(Roles="Admin")] or even the [Authorize] only functions if I leave only that (and remove the global.asax part). Why?

HTTPContext User Set In BeginRequest Not Available In Controller

I am rolling with a somewhat homebrew method of authenticating users. After authenticating the user, the authentication ticket is set like so in C#.
FormsAuthenticationTicket authenticationTicket = new FormsAuthenticationTicket(1, viewModel.Email, DateTime.Now, DateTime.Now.AddHours(48), true, String.Join("|", roles));
string encryptedTicket = FormsAuthentication.Encrypt(authenticationTicket);
HttpCookie authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
Response.Cookies.Add(authCookie);
With a small note that roles is a string list built out of the available roles to that user (The roles are not within the same user table - e.g. there is a set of conditions that define a user "role").
Next within the Application_BeginRequest method in Global.asax I have the following :
// Extract the forms authentication cookie
string cookieName = FormsAuthentication.FormsCookieName;
HttpCookie authCookie = Context.Request.Cookies[cookieName];
if (null == authCookie)
{
return;
}
FormsAuthenticationTicket authTicket = null;
try
{
authTicket = FormsAuthentication.Decrypt(authCookie.Value);
}
catch (Exception ex)
{
return;
}
if (null == authTicket)
{
return;
}
string[] roles = authTicket.UserData.Split(new char[] { '|' });
FormsIdentity id = new FormsIdentity(authTicket);
GenericPrincipal principal = new GenericPrincipal(id, roles);
HttpContext.Current.User = principal;
Basically setting the current context with the user from the authticket. However, I first ran into an issue as I was doing a custom Authorize attribute for an MVC class, and I noticed that the User of the HTTPContext was NOT set.
I then noticed that within each action, the User was not set either. I can clearly see however by stepping through my code, that the user IS being found within the authentication ticket and being decrypted OK and stored in the context variable. But by the time I get to an action within any controller, the User has vanished from the context.
EDIT :
It should also be noted that other values set on the HTTPContext do carry over to the controller. e.g. this line
HttpContext.Current.AllowAsyncDuringSyncStages = false; // Or true
Will carry whatever I set it to into the controller action. It seems to only be the User that gets blanked.
Application_BeginRequest is not a valid place to set HttpContext.Current.User, As it will be overwritten during Authorization.
You need to implement the above code in Application_AuthorizeRequest.For example refer to below code. Then it will be available in controller.
public MvcApplication()
{
this.AuthorizeRequest += MvcApplication_AuthorizeRequest;
}
void MvcApplication_AuthorizeRequest(object sender, EventArgs e)
{
FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket("test", true, 30);
FormsIdentity id = new FormsIdentity(authTicket);
GenericPrincipal principal = new GenericPrincipal(id, new string[] { });
HttpContext.Current.User = principal;
}

Categories

Resources