How can i create a cookie step by step,
that stores the user login id and password when he/she clicks Remember Me? option
and i am planing to kill this cookie after certain time
Cookies are created the same way as they are in plain old ASP.NET, you just need to access the Response.
public ActionResult Login(string username, string password, bool rememberMe)
{
// validate username/password
if (rememberMe)
{
HttpCookie cookie = new HttpCookie("RememberUsername", username);
Response.Cookies.Add(cookie);
}
return View();
}
However, if you're using Forms Auth, you can just make your FormsAuth ticket cookie persistent:
public ActionResult Login(string username, string password, bool rememberMe)
{
// validate username/password
FormsAuthentication.SetAuthCookie(username, rememberMe);
return View();
}
You can read cookies like this:
public ActionResult Index()
{
var cookie = Request.Cookies["RememberUsername"];
var username = cookie == null ? string.Empty : cookie.Value; // if the cookie is not present, 'cookie' will be null. I set the 'username' variable to an empty string if its missing; otherwise i use the cookie value
// do what you wish with the cookie value
return View();
}
If you are using Forms Authentication and the user is logged in, you can access their username like this:
public ActionResult Index()
{
var username = User.Identity.IsAuthenticated ? User.Identity.Name : string.Empty;
// do what you wish with user name
return View();
}
It is possible to decrypt and read the contents of a ticket. You can even store small amounts of custom data in the ticket, if you need to. See this article for more info.
Related
I am working on an asp.net MVC4 web application, and for the login i am using form authentication that is connected to our AD using LDAP connection string, as follow.
The login Get action method:-
[AllowAnonymous]
public ActionResult Login(string returnUrl)
{
returnUrl = TempData["returnUrl"] != null ? TempData["returnUrl"].ToString() : String.Empty;
List<String> domains = new List<String>();
domains.Add("*****");
ViewBag.ReturnUrl = returnUrl;
ViewBag.Domains = domains;
return View();
}
The Login Post action method:-
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Login(LoginModel model, string returnUrl)
{
MembershipProvider domainProvider;
domainProvider = Membership.Providers["TestDomain1ADMembershipProvider"];
if (ModelState.IsValid)
{
// Validate the user with the membership system.
if (domainProvider.ValidateUser(model.UserName, model.Password))
{
FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
}
else
{
ModelState.AddModelError("", "The user name or password provided is incorrect.");
List<String> domains2 = new List<String>();
domains2.Add("****");
ViewBag.Domains = domains2;
return View(model);
}
return RedirectToLocal(returnUrl);
}
List<String> domains = new List<String>();
domains.Add("****");
ViewBag.Domains = domains;
return View(model);
}
Now i have been using this system for 5 years and never face any issue with user login. but today a new user mentioned that when he tried to login to the system he will get an error "Error while processing your request.", and this error will be raised in our system if an unhandled exception is being raised. and i checked the IIS log and i can see that the user did not access the system.
so the only issue i can think of is that the user's password contain characters which MVC does not allow. for example i tried to type this password <script>#1234 along with my username, and instead of getting this message "The user name or password provided is incorrect." , i got the same exception "Error while processing your request.".. of course i can not ask the user to mention his password, but i am not sure how i can allow MVC to accept any password passed to it? as i can not think of any other problem...because usually when users login to the application they either; login successfully Or get "The user name or password provided is incorrect." , but i never face a problem where the user get an exception... which i were able to replicate by passing unsafe characters <script>#1234
In your LoginModel make add the AllowHtmlAttribute to the Password field. This will bypass the check against input like <script>.
[AllowHtml]
public string Password { get; set; }
Use it sparing, of course. MVC is trying to protect you from script injection attacks, so you should only disable this check in a few cases where you can be sure the value is handled safely. (In this case, passwords should never be displayed to the user, so even if there is HTML in it, it cannot inject HTML onto the page).
Alternatively, if you cannot alter the LoginModel class, you could try adding the ValidateInputAttribute to your Login POST method.
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
[ValidateInput(false)]
public ActionResult Login(LoginModel model, string returnUrl)
Inside my HomeController where page requests are processed, I'm attempting to retrieve a value for a cookie.
public ActionResult Index() {
var userCook = Response.Cookies.Get("user");
whatever = userCook.Value;
return View();
}
Simply trying to retrieve the cookie "user", which should have a value of "admin", causes the cookie to be deleted from the client and end up with a value of nothing.
Note I have also tried:
public ActionResult Index() {
string userCook = Response.Cookies["user"].Value;
return View();
}
These both delete the cookie and recreate a new cookie with the name "user" despite there already being a cookie called user with a value.
I have this problem. When user log in, I create cookie with formsauthanticationticket:
var formAuthTicket = new FormsAuthenticationTicket(1, model.UserName, DateTime.Now, DateTime.Now.AddMinutes(1), false, "");
var encryptedFormAuthTicket = FormsAuthentication.Encrypt(formAuthTicket);
var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedFormAuthTicket);
Response.Cookies.Add(cookie);
return RedirectToAction("Index", "Home");
Now. In PreRequestHandlerExecute event i check, if user is authenticated/cookie exists.
var cookie = context.Request.Cookies[FormsAuthentication.FormsCookieName];
if (cookie != null)
{
var formAuthTicket = FormsAuthentication.Decrypt(cookie.Value);
var newFormAuthTicket = new FormsAuthenticationTicket(formAuthTicket.Version, formAuthTicket.Name,
formAuthTicket.IssueDate,
DateTime.Now.AddMinutes(1),
formAuthTicket.IsPersistent,
formAuthTicket.UserData,
FormsAuthentication.FormsCookiePath);
cookie.Value = FormsAuthentication.Encrypt(newFormAuthTicket);
context.Response.Cookies.Set(cookie);
}
But when cookie not exists/expired I want to redirect the user to login page, when he clicks on some link. Any idea?
Thanks
EDIT
Because I can't use Authorize attribute. I know about it. I have httpmodule, in assembly, which is referenced in web project. In httpmodule I have Init method, where I initialize PreRequestHandlerExecute() event. In the event I check authentication of user. If I use in "else" something like this -> Response.Redirect(url), occurs cycle redirection, that's wrong. After 10minutes without any request, user clicks some link, he will be redirected to login page -> that's my problem, I can't solve.
Why you just don't use the [Authorize] attribute? Added in the sign of your action and if the cookie related with authentication expired will be automatically redirected to the login Page
For example
[Authorize]
public ActionResult Profile()
{
}
And if you need a custom implementation created your custom attribute implement the interface for example
public class FooAuthorizeAttribute : AuthorizeAttribute
{
public string fooField{ get; set; }
public override void OnAuthorization(AuthorizationContext filterContext)
{
//Do my stuff
}
Then called in your action
[FooAuthorizeAttribute]
public ActionResult Profile()
{
}
Just wondering what the best way to store user login data on successful login in my application. I.e. when logged in at the moment I do something like this in my login script
Session("loggedIn") = "Yes"
Session("userName") = reader_login("useremail").ToString()
Session("userId") = reader_login("user_ID").ToString()
Session("firstName") = reader_login("firstName").ToString()
Session("lastName") = reader_login("lastName").ToString()
And then I use these session variables on my scripts, but just noticed that every time I want to use some of these session variables I do need to check if they are nut null before calling them, seems a bit clumsy to repeat these for a lot of my .aspx pages. Is there a better way to do this ?
EDIT :
Also I am wondering why do I need to add the IS NUll check for the session on each script I use session variables I put the check in the master page but noticed I still get null exception in my usercontrol which is referenced in my master page but does not have the IS null check
Session is not the way to check whether user is authenticated or not. Session may be cleared on demand by administrator when clearing app pool, or by the low memory on server. You won't wish to log out user in such cases. The builtin and reccommended way for doing this in ASP.NET is storing data in authentication cookie. Once the user is logged in, you issue the cookie that contains all the data, including user id, name, etc. And then, you don't have to check every property in session for null, more simple - you just check if the user is authenticated - then you've got the data, else -not. And the other benefit, if you substitute builtin principal with custom one, you can define strongly typed object that holds user data, no more casting from objects extracted from session. Here're the examples for defining custom principal with forms authentication
First, let's define custom MyIdentity and MyPrincipal
public class MyIdentity : IIdentity
{
private FormsAuthenticationTicket _Ticket;
private int _userId = 0;
public FormsAuthenticationTicket Ticket
{
get { return _Ticket; }
}
public string Name
{
get { return _Ticket.Name; }
}
public int UserId
{
get
{
if (_userId == 0)
_userId = Convert.ToInt32(_Ticket.UserData.Split("|".ToCharArray())[0]);
return _userId;
}
}
public Identity(FormsAuthenticationTicket ticket)
{
this._Ticket = ticket;
}
public string AuthenticationType
{
get { return "Custom"; }
}
public bool IsAuthenticated
{
get { return UserId > 0; }
}
}
Then the MyPrincipal that holds MyIdentity
public class MyPrincipal : IPrincipal
{
private MyIdentity _Identity;
public Principal(MyIdentity identity)
{
_Identity = identity;
}
public IIdentity Identity
{
get { return _Identity; }
}
public bool IsInRole(string role)
{
return false;
}
}
Then substitute original forms user with the custom one. In Global.asax
private void Application_OnPostAuthenticateRequest(object sender, EventArgs e)
{
IPrincipal usr = HttpContext.Current.User;
// If we are dealing with an authenticated forms authentication request
if (usr.Identity.IsAuthenticated && usr.Identity.AuthenticationType == "Forms")
{
FormsIdentity formsIdentity = usr.Identity as FormsIdentity;
// Create a CustomIdentity based on the FormsAuthenticationTicket
IIdentity identity = new MyIdentity(formsIdentity.Ticket);
IPrincipal principal = new MyPrincipal(identity);
// Attach the CustomPrincipal to HttpContext.User and Thread.CurrentPrincipal
HttpContext.Current.User = principal;
Thread.CurrentPrincipal = principal;
}
}
Define method for issuing forms authentication ticket. Later, the custom MyIdentity class will extract userId and other methods from userData.
public static HttpCookie GetAuthCookie(string userName, string userData, bool createPersistentCookie, HttpSessionStateBase session)
{
HttpCookie authCookie = FormsAuthentication.GetAuthCookie(userName, createPersistentCookie);
FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(authCookie.Value);
FormsAuthenticationTicket newTicket = new FormsAuthenticationTicket(ticket.Version, ticket.Name, ticket.IssueDate, ticket.Expiration, ticket.IsPersistent, userData, session.SessionID);
authCookie.Value = FormsAuthentication.Encrypt(newTicket);
return authCookie;
}
When the user is checked and is authenticated, return them authentication cookie
Response.Cookies.Add(AuthenticationCookie.GetAuthCookie(model.UserName, GetUserInfo(model.UserName, passwordHash), model.RememberMe, Session));
//GetUserInfo returns | separated string of user datas. "userId|userName|firstName|lastName" for example.
And at last, using all of the above in code
if(User.Identity.IsAuthenticated)
{
int userId = ((MyIdentity)User.Identity).UserId;
}
This may seem the larger code, but in runtime it'll give much more benefits than storing all the data in session. The main of them are null checking and casting every time.
You could load this through a single object which you put in the Session. This will remove all your strings as you can just set properties. Also you can check if the object is available in the session, if it's not the user is not logged in?
public class CurrentUserObject
{
public string UserName { get; set; }
public string UserID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public CurrentUserObject(string userName, string userID, string firstName, string lastName)
{
UserName = userName;
UserID = userID;
FirstName = firstName;
LastName = lastName;
}
}
You can instantiate this object and store it in Session("CurrentUser") or something. If you request this session variable and it turns out to be null, your user is not logged in. I would advise you to do this in a master page or something by the way to avoid duplication of this code.
you don't have to store "loggedIn" in session.
you can use Session["userName"] to check, if it is null, not logged in; not null, logged in.
try to use one session item to track user login status, such username or userid.
also you can encapsule the logic into a method such as
static bool CheckLogin(HttpSession sessionState, out username, out userId, out firstName, out LastName);
FYI
may be you need to use caching in your application because you are going to check if null or not every time i think for save use data caching will be better and here are some links :
http://msdn.microsoft.com/en-us/library/xsbfdd8c(v=vs.71).aspx
http://msdn.microsoft.com/en-us/library/ms972379.aspx
http://www.exforsys.com/tutorials/asp.net/caching-in-asp.net.html
http://www.codeproject.com/KB/web-cache/cachingaspnet.aspx
Hope it helps mark as answered if it helps :)
i have change the default Account Membership provider to set IsApproved to false.
public MembershipCreateStatus CreateUser(string userName, string password, string email)
{
MembershipCreateStatus status;
_provider.CreateUser(userName, password, email, null, null, false, null, out status);
return status;
}
But i then go back to the login page and it allows me to login. Shouldn't it fail login and say that i am not approved ??
EDIT:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Register(string userName, string email, string password, string confirmPassword, string address, string address2, string city, string state, string homePhone, string cellPhone, string company)
{
ViewData["PasswordLength"] = MembershipService.MinPasswordLength;
if (ValidateRegistration(userName, email, password, confirmPassword))
{
// Attempt to register the user
MembershipCreateStatus createStatus = MembershipService.CreateUser(userName, password, email);
if (createStatus == MembershipCreateStatus.Success)
{
FormsAuth.SignIn(userName, false /* createPersistentCookie */);
TempData["form"] = Request.Form;
TempData["isActive"] = false;
return RedirectToAction("Create", "Users");
}
else
{
ModelState.AddModelError("_FORM", ErrorCodeToString(createStatus));
}
}
// If we got this far, something failed, redisplay form
return View();
}
(it looks like the other copy of this question is going to be closed, so I've copied my answer here)
HttpRequest.IsAuthenticated returns true if HttpContext.User.Identity is not null and it's IsAuthenticated property returns true.
The current identity is set in the FormsAuthenticationModule, but it has nothing to do with your MembershipProvider. In fact, it doesn't even reference it. All it does is check to see if the authentication cookie is still set and is still valid (as is, has not expired).
I think the problem is that you are calling one of the FormsAuthentication methods like RedirectFromLoginPage, which is settings the authentication cookie. If you need to wait until the user is approved, then you need to make sure you are not setting the cookie.
Update
There are no values of MembershipCreateStatus that specify that the user has been created but not approved, so your code is calling FormsAuth.SignIn without actually checking if the user has been approved.
FormsAuth.SignIn just sets the cookie, that's it. It doesn't validate the user or otherwise have any relation to your MembershipProvider. If approval is asynchronous (ie. waiting for a human), then don't automatically log the user in by calling FormsAuth.SignIn.