I have a problem with cookies in MVC3. I want to create a cookie, that stores informations whether the user is logged in. I have never used cookies before and don't know what is the proper way to do it and I am new to MVC3.
Please, can somebody tell me if the approach I used to store cookie is proper or if there is some security risk (the password is encrypted)?
If the cookies are set correctly, how can I use them in other views to check if the user is logged in and set the session for him?
If the approach I use to log in user is wrong, just tell me.
public ActionResult Login(string name, string hash, string keepLogged)
{
if (string.IsNullOrWhiteSpace(hash))
{
Random random = new Random();
byte[] randomData = new byte[sizeof(long)];
random.NextBytes(randomData);
string newNonce = BitConverter.ToUInt64(randomData, 0).ToString("X16");
Session["Nonce"] = newNonce;
return View(model: newNonce);
}
User user = model.Users.Where(x => x.Name == name).FirstOrDefault();
string nonce = Session["Nonce"] as string;
if (user == null || string.IsNullOrWhiteSpace(nonce))
{
return RedirectToAction("Login", "Users");
}
string computedHash;
using (SHA256 sha256 = SHA256.Create())
{
byte[] hashInput = Encoding.ASCII.GetBytes(user.Password + nonce);
byte[] hashData = sha256.ComputeHash(hashInput);
StringBuilder stringBuilder = new StringBuilder();
foreach (byte value in hashData)
{
stringBuilder.AppendFormat("{0:X2}", value);
}
computedHash = stringBuilder.ToString();
}
if (computedHash.ToLower() == hash.ToLower())
{
Session["IsAdmin"] = user.IsAdmin == 1;
Session["IDUser"] = user.IDUser;
ViewBag.IdUser = IDUser;
ViewBag.IsAdmin = IsAdmin;
ViewBag.UserName = model.Users.Where(x => x.IDUser == IDUser).First().Name;
if (keepLogged == "keepLogged")
{
//Set user's cookies - is this correct?
Response.Cookies.Add(new HttpCookie("UserCookie", user.IDUser.ToString()));
Response.Cookies.Add(new HttpCookie("PassCookie", user.Password.ToString()));
}
}
return RedirectToAction("Index", "Posts");
}
This code creates an encrypted cookie with the username
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(
1,
user.UserName,
DateTime.Now,
DateTime.Now.AddMinutes(10),
false,
null);
string encryptedTicket = FormsAuthentication.Encrypt(ticket);
HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
this.Response.Cookies.Add(cookie);
To enable forms authentication add the following to the system.web section of the web.config:
<authentication mode="Forms">
<forms loginUrl="~/Logon" timeout="2880" />
</authentication>
No,You do not want to store the user's password in a custom cookie. Look into Forms Authetication. It does all the cookie work for you. You can set that forms authetication cookie to persist on the user's computer so that they "stay logged in".
here is my simlified version how you can work with cookies
for remember user name
/// <summary>
/// Account controller.
/// </summary>
public ActionResult LogOn()
{
LogOnModel logOnModel = new LogOnModel();
HttpCookie existingCookie = Request.Cookies["userName"];
if (existingCookie != null)
{
logOnModel.UserName = existingCookie.Value;
}
return View(logOnModel);
}
public ActionResult LogOn(LogOnModel model, string returnUrl)
{
if (model.RememberMe)
{
// check if cookie exists and if yes update
HttpCookie existingCookie = Request.Cookies["userName"];
if (existingCookie != null)
{
// force to expire it
existingCookie.Value = model.UserName;
existingCookie.Expires = DateTime.Now.AddHours(-20);
}
// create a cookie
HttpCookie newCookie = new HttpCookie("userName", model.UserName);
newCookie.Expires = DateTime.Today.AddMonths(12);
Response.Cookies.Add(newCookie);
}
// If we got this far, something failed, redisplay form
return View(model);
}
Related
I am using MVC but I have a problem of dispose method is being called. When I am going to login, all the validation and login is working properly but when I am redirecting after a successful login, then in the case of return redirect to action, dispose method is being called.
What should I do?
Here is my controller:
public UserManager<ApplicationUser> UserManager { get; private set; }
public AdminController()
: this(new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext())))
{
}
public AdminController(UserManager<ApplicationUser> userManager)
{
UserManager = userManager;
}
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Login(LoginViewModel model, string returnUrl)
{
if (Session["RoleID"] != null)
{
if (Convert.ToInt32(Session["RoleID"]) == Ansits2018.UTILITIES.Constants.Admin)
{
return RedirectToAction("Index", "Admin");
}
}
if (ModelState.IsValid)
{
var accRepo = new AccountRepository();
int UserID = 0;
UserID = accRepo.IsUserValid(model.UserName, model.Password);
if (UserID > 0)
{
var user = accRepo.GetUserByUsername(model.UserName);
Session["CompanyID"] = 1;
Session["UserID"] = UserID;
Session["Username"] = model.UserName;
Session["RoleID"] = user.RoleID;
Session["Name"] = user.Name;
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(
1, // ticket version
user.Username, // authenticated username
DateTime.Now, // issueDate
DateTime.Now.AddMinutes(60), // expiryDate
true, // true to persist across browser sessions
user.RoleID.ToString(), // can be used to store additional user data
FormsAuthentication.FormsCookiePath // the path for the cookie
);
// Encrypt the ticket using the machine key
string encryptedTicket = FormsAuthentication.Encrypt(ticket);
// Add the cookie to the request to save it
HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
cookie.HttpOnly = true;
Response.Cookies.Add(cookie);
if (!String.IsNullOrEmpty(returnUrl))
{
return RedirectToLocal(returnUrl);
}
if (user.RoleID == Ansits2018.UTILITIES.Constants.Admin)
{
return RedirectToAction("Index", "Admin");
}
}
else
{
TempData["Message"] = "Invalid username or password.";
return View(model);
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
protected override void Dispose(bool disposing)
{
if (disposing && UserManager != null)
{
UserManager.Dispose();
UserManager = null;
}
base.Dispose(disposing);
}
RedirectToAction (at least the form you're using) is constructed like this:
RedirectToAction(string actionName, string controllerName)
So return RedirectToAction("Index", "Home"); takes you to the Index action in the Home Controller, and return RedirectToAction("Index", "Admin"); takes you to the Index Action of the Admin Controller.
So if I'm reading your question correctly, you need to change the code to return RedirectToAction("Index", "Home");
Update (in light of comments):
If you are wanting to RedirectToAction("Index", "Admin"); then you'll need to debug your code to find out where the problem is. You can set breakpoints for the debug, or add these debug lines to your code:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Login(LoginViewModel model, string returnUrl)
{
if (Session["RoleID"] != null)
{
if (Convert.ToInt32(Session["RoleID"]) == Ansits2018.UTILITIES.Constants.Admin)
{
return RedirectToAction("Index", "Admin");
}
}
if (ModelState.IsValid)
{
var accRepo = new AccountRepository();
int UserID = 0;
UserID = accRepo.IsUserValid(model.UserName, model.Password);
if (UserID > 0)
{
var user = accRepo.GetUserByUsername(model.UserName);
Session["CompanyID"] = 1;
Session["UserID"] = UserID;
Session["Username"] = model.UserName;
Session["RoleID"] = user.RoleID;
Session["Name"] = user.Name;
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(
1, // ticket version
user.Username, // authenticated username
DateTime.Now, // issueDate
DateTime.Now.AddMinutes(60), // expiryDate
true, // true to persist across browser sessions
user.RoleID.ToString(), // can be used to store additional user data
FormsAuthentication.FormsCookiePath // the path for the cookie
);
// Encrypt the ticket using the machine key
string encryptedTicket = FormsAuthentication.Encrypt(ticket);
// Add the cookie to the request to save it
HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
cookie.HttpOnly = true;
Response.Cookies.Add(cookie);
if (!String.IsNullOrEmpty(returnUrl))
{
System.Diagnostics.Debug.WriteLine("1 #####> RedirectToLocal (valid Login): " + returnUrl);
return RedirectToLocal(returnUrl);
}
if (user.RoleID == Ansits2018.UTILITIES.Constants.Admin)
{
return RedirectToAction("Index", "Admin");
}
}
else
{
System.Diagnostics.Debug.WriteLine("2 #####> Invalid Login Attempt - UserID > 0: " + model.UserName + " => " + model.Password));
TempData["Message"] = "Invalid username or password.";
return View(model);
}
}
System.Diagnostics.Debug.WriteLine("3 #####> ModelState Invalid: " + model.UserName + " => " + model.Password);
return View(model);
}
then click the cursor on the Login View Action (not the [HttpPost]), hit Debug in the menu and then Start Debugging. Wait for it to all settle down and then login and watch the Debug messages to see which one appears. That should give a good clue as to what's going wrong, and what you need to do.
I have created a Website in ASP.Net MVC5 and used a login function in it, it works fine on localhost but when I uploaded the site server,
Server redirects me to the login page on each click.
Below is login Function
public ActionResult DoLogin(string username, string password)
{
if (!string.IsNullOrEmpty(username) && !string.IsNullOrEmpty(password))
{
var user = new UserRepository().GetAll()
.Where(u => u.UserName.ToUpper() == username.Trim().ToUpper()
&& u.Password == password).SingleOrDefault();
if (user != null)
{
FormsAuthentication.SetAuthCookie(user.UserName,true);
var authTicket = new FormsAuthenticationTicket(1, user.UserName, DateTime.Now, DateTime.Now.AddHours(24), true, user.Roles);
string encryptedTicket = FormsAuthentication.Encrypt(authTicket);
var authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
HttpContext.Response.Cookies.Add(authCookie);
Session["Name"] = user.Name;
return RedirectToAction("Index", "Student");
}
}
ViewBag.ErrorMessage = "User Name or Password is incorrect";
return View("Login");
}
then I added the below function in Global.asax.cs File.
protected void Application_PostAuthenticateRequest(Object sender, EventArgs e)
{
var authCookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];
if (authCookie != null)
{
FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value);
if (authTicket != null && !authTicket.Expired)
{
var roles = authTicket.UserData.Split(',');
HttpContext.Current.User = new System.Security.Principal.GenericPrincipal(new FormsIdentity(authTicket), roles);
}
}
}
After that I have added [Authorize(Roles = "Admin")] before each Controller (Not before methods in Controller) I want to Restrict access to.
Now, whenever I login, It redirects me to Index Method of Student controller, after that I click on some other link it again takes me to the Login page. Sometimes it takes me to clicked link without taking me to Login Page. Whats the Problem with my code? it works fine on localhost.
You are assigning the auth ticket twice;
if (user != null)
{
//FormsAuthentication.SetAuthCookie(user.UserName,true); Remove it
var authTicket = new FormsAuthenticationTicket(1, user.UserName, DateTime.Now, DateTime.Now.AddHours(24), true, user.Roles);
string encryptedTicket = FormsAuthentication.Encrypt(authTicket);
var authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
HttpContext.Response.Cookies.Add(authCookie);
Session["Name"] = user.Name;
return RedirectToAction("Index", "Student");
}
Also, I suggest you to don't store the roles in cookie because if the user role has been removed or added new one, you can't update them. So,
protected void Application_PostAuthenticateRequest(Object sender, EventArgs e)
{
var authCookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];
if (authCookie != null)
{
FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value);
if (authTicket != null && !authTicket.Expired)
{
var roles = authTicket.UserData.Split(',');//fill it from database and it could be better to use cache mechanism for performance concern
HttpContext.Current.User = new System.Security.Principal.GenericPrincipal(new FormsIdentity(authTicket), roles);
}
}
}
I am trying to add an option to my web page, so that when a user logs in to have a 'remember me' option. To implement this I am trying to store the user data (name+password) in a cookie, but it's not working at the moment.
My code to store the cookie is:
int timeout = 525600;
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(model.UserName, true, timeout);
string encrypted = FormsAuthentication.Encrypt(ticket);
HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encrypted);
cookie.Expires = System.DateTime.Now.AddMinutes(timeout);
System.Web.HttpContext.Current.Response.Cookies.Add(cookie);
FormsAuthentication.SetAuthCookie(model.UserName, true);
Request.Cookies.Add(cookie);
and on my logIn controller my code looks like:
HttpCookie cookie = System.Web.HttpContext.Current.Request.Cookies.Get(FormsAuthentication.FormsCookieName);
if (cookie != null)
{
FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(cookie.Value);
var userName = ticket.UserData;
}
The problem is that the userData cookie is always empty. What am I missing?
Try this.
Creating/Writing Cookies
Way 1
`HttpCookie StudentCookies = new HttpCookie("StudentCookies");
StudentCookies.Value = TextBox1.Text;
StudentCookies.Expires = DateTime.Now.AddHours(1);
Response.Cookies.Add(StudentCookies);`
Way 2
Response.Cookies["StudentCookies"].Value = TextBox1.Text;
Response.Cookies["StudentCookies"].Expires = DateTime.Now.AddDays(1);
Way 3
Response.Cookies["StudentCookies"]["RollNumber"] = TextBox1.Text;
Response.Cookies["StudentCookies"]["FirstName"] = "Abhimanyu";
Response.Cookies["StudentCookies"]["MiddleName"] = "Kumar";
Response.Cookies["StudentCookies"]["LastName"] = "Vatsa";
Response.Cookies["StudentCookies"]["TotalMarks"] = "499";
Response.Cookies["StudentCookies"].Expires = DateTime.Now.AddDays(1);
Reading/Getting Cookies
string roll = Request.Cookies["StudentCookies"].Value;
Deleting Cookies
if (Request.Cookies["StudentCookies"] != null)
{
Response.Cookies["StudentCookies"].Expires = DateTime.Now.AddDays(-1);
Response.Redirect("Result.aspx"); //to refresh the page
}
reference here
I am trying to use SimpleMembershipProvider for FormsAuthentication. Now this provider internally creates a FormsAuth cookie without any additional userdata.
I want to include some other information in the cookie such as UserId, Role, etc
I have implemented following-
public class MyAuthorizeAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
var isAuthorized = base.AuthorizeCore(httpContext);
if (isAuthorized)
{
var formsCookie = httpContext.Request.Cookies[FormsAuthentication.FormsCookieName];
var identity = new AppUserIdentity(string.Empty, true);
if (formsCookie != null)
{
var cookieValue = FormsAuthentication.Decrypt(formsCookie.Value);
if (cookieValue != null && !string.IsNullOrEmpty(cookieValue.UserData))
{
var cookieData = SerializerXml.Deserialize<UserNonSensitiveData>(cookieValue.UserData);
identity = new AppUserIdentity(cookieValue.Name, cookieData.UserId, true);
}
else if (cookieValue != null)
{
//TODO: Find out technique to get userid value here
identity = new AppUserIdentity(cookieValue.Name, null, true);
}
}
var principal = new AppUserPrincipal(identity);
httpContext.User = Thread.CurrentPrincipal = principal;
}
return isAuthorized;
}
}
This attribute is decorated on all required controller methods. When a user registers or login on the website I am updating the cookie as well with additional userdata (serialized string)
var newticket = new FormsAuthenticationTicket(ticket.Version,
ticket.Name,
ticket.IssueDate,
ticket.Expiration,
ticket.IsPersistent,
userdata,
ticket.CookiePath);
// Encrypt the ticket and store it in the cookie
cookie.Value = FormsAuthentication.Encrypt(newticket);
cookie.Expires = newticket.Expiration.AddHours(24);
Response.Cookies.Set(cookie);
However, in MyAuthorizeAttribute it never gets userdata in the cookie. Is there anything wrong in the above code? Or something missing somewhere else?
Found the answer to this question,
check out the link
http://www.codetails.com/2013/05/25/using-claims-identity-with-simplemembership-in-asp-net-mvc/
I am creating a cookie and storing the value of username after succesfull login. How can I access the cookie when the website is opened. If the cookie exist I want to fill the username text box from the cookie value. And how to decrypt the value to get the username. I am doing server side validation by getting the userdetails from the database. I am using vs 2010 with c#
FormsAuthenticationTicket tkt;
string cookiestr;
HttpCookie ck;
tkt = new FormsAuthenticationTicket(1, txtUserName.Value, DateTime.Now,
DateTime.Now.AddYears(1), chk_Rememberme.Checked, "User Email");
cookiestr = FormsAuthentication.Encrypt(tkt);
ck = new HttpCookie(FormsAuthentication.FormsCookieName, cookiestr);
if (chk_Rememberme.Checked)
{
ck.Expires = tkt.Expiration;
ck.Path = FormsAuthentication.FormsCookiePath;
Response.Cookies.Add(ck);
}
cookie is created with name as .YAFNET_Authentication and content is encrypted
Webconfig:
<forms name=".YAFNET_Authentication" loginUrl="Home.aspx"
protection="All" timeout="15000" cookieless="UseCookies"/>
You may use Request.Cookies collection to read the cookies.
if(Request.Cookies["key"]!=null)
{
var value=Request.Cookies["key"].Value;
}
FormsAuthentication.Decrypt takes the actual value of the cookie, not the name of it. You can get the cookie value like
HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName].Value;
and decrypt that.
add this function to your global.asax
protected void Application_AuthenticateRequest(Object sender, EventArgs e)
{
string cookieName = FormsAuthentication.FormsCookieName;
HttpCookie authCookie = Context.Request.Cookies[cookieName];
if (authCookie == null)
{
return;
}
FormsAuthenticationTicket authTicket = null;
try
{
authTicket = FormsAuthentication.Decrypt(authCookie.Value);
}
catch
{
return;
}
if (authTicket == null)
{
return;
}
string[] roles = authTicket.UserData.Split(new char[] { '|' });
FormsIdentity id = new FormsIdentity(authTicket);
GenericPrincipal principal = new GenericPrincipal(id, roles);
Context.User = principal;
}
then you can use HttpContext.Current.User.Identity.Name to get username. hope it helps
HttpCookie cook = new HttpCookie("testcook");
cook = Request.Cookies["CookName"];
if (cook != null)
{
lbl_cookie_value.Text = cook.Value;
}
else
{
lbl_cookie_value.Text = "Empty value";
}
Reference Click here