ASP.Net simple login page - c#

I am trying to make a simple log in page in ASP.net and this is my code:
protected void Submit1_Click(object sender, EventArgs e)
{
// Validate the user against the Membership framework user store
if (Membership.ValidateUser(UserName.Text, Password.Text))
{
// Log the user into the site
FormsAuthentication.RedirectFromLoginPage(UserName.Text, Persist.Checked);
Response.Redirect("test-records.aspx");
}
// If we reach here, the user's credentials were invalid
Msg.Visible = true;
}
I don't know whats wrong because it shows no error and it just refreshes with no error
even the label msg is not visible.

If your using a MembershipProvider, and since it seems that there is nothing special have been done in your code, why not use the Login Control, and give it the membership provider class, and thats it!.

Related

How do I know which user's session id has been expired (and which users are online?)

I am developing an online chess game. After a user presses the login button, I save userid in a session variable:
Session["userID"] = userId.Text;
After assigning the variable, the user is transferred to another page.
There is a possibility more then one user is online at a time. Let say three user are online at a time and in session variable one user contain "1" userId, next contain "2" and so on.
If one of the user's Session Id expires for some reason, how do I know which user's session expired?
The reason is I want to show the other users that this particular user is not online anymore.
How do I know which user session variable expired?
You can subscribe to the SessionStateModule.End event:
public class KyuApplication : System.Web.HttpApplication
{
public override void Init()
{
SessionStateModule session = Modules["Session"] as SessionStateModule;
if (session != null)
{
session.Start += new EventHandler(Session_Start);
session.End += new EventHandler(Session_End);
}
}
private void Session_Start(object sender, EventArgs e)
{
System.Diagnostics.Debug.WriteLine("Session_Start");
}
private void Session_End(object sender, EventArgs e)
{
System.Diagnostics.Debug.WriteLine("Session_End");
}
}
Example from: http://johnllao.wordpress.com/2009/06/05/session_start-and-session_end-event-from-custom-httpapplication/
The reason is I want to show the other users that this particular user is not online anymore.
You approach is unnecessary. The Asp.Net membership framework provides this functionality for you so you don't have to build it yourself. You can use MembershipUser.IsOnline to do this for you.
Example from MSDN:
MembershipUserCollection users;
public void Page_Load()
{
users = Membership.GetAllUsers();
if (!IsPostBack)
{
// Bind users to ListBox.
UsersListBox.DataSource = users;
UsersListBox.DataBind();
}
// If a user is selected, show the properties for the selected user.
if (UsersListBox.SelectedItem != null)
{
MembershipUser u = users[UsersListBox.SelectedItem.Value];
EmailLabel.Text = u.Email;
IsOnlineLabel.Text = u.IsOnline.ToString();
LastLoginDateLabel.Text = u.LastLoginDate.ToString();
CreationDateLabel.Text = u.CreationDate.ToString();
LastActivityDateLabel.Text = u.LastActivityDate.ToString();
}
}
Here are some additional blog posts that discuss this in more detail and describe how to set it up:
http://dotnetslackers.com/articles/aspnet/tracking-user-activity.aspx
http://blog.dreamlabsolutions.com/post/2009/07/13/ASPNET-Membership-Show-list-of-users-online.aspx
Session data is meant to be private to the user and is not meant to be accessible to the rest of your application (that is, outside the user's context). That means that doing what you want using the session is going to be hard and awkward.
A better alternative would be to track user activity in a separate datastructure and keep that in the web server's memory (using a static variable or the System.Web.Caching namespace) or in the database.
For every user you can save session information in remote storage (database for example) with expiration date (that must be MORE than the session expiration date from application configuration) and userID binding and after user is making some action in your application you can change the expiration date by adding some value. So that in this case you always have the list of not expired sessions, controled by you.
With Session variable - you can see session information just about the current request from the client. So that using just this variable you sure can't see other users' sessions, that would be just unsecure.
You can use the SessionStateModule.End Event to catch that.

How to redirect to a particular page after getting logged in, in membership?

I am using asp.net membership, I have few pages at the root like loin, register, forget pass, that are accessible to all users before they log in or not registered, I want to stop these pages to accessible once user get logged in, I mean if a user manually type the URL in the Address Bar it allows to access those pages how to prevent this?
Also, I am facing a problem how to redirect to a particulate page after getting logged in.
to redirect once Logged in check FormAuthentication.RedirectfromLoginPage
public void Login_OnClick(object sender, EventArgs args)
{
if (Membership.ValidateUser(UsernameTextbox.Text, PasswordTextbox.Text))
FormsAuthentication.RedirectFromLoginPage(UsernameTextbox.Text, NotPublicCheckBox.Checked);
else
Msg.Text = "Login failed. Please check your user name and password and try again.";
}
and you can check whether user is authenticated or not by
Page.User.Identity.IsAuthenticated
Check this links for forms authentications
FormsAuthentication
FormAutentication MSDN
You can use UrlReferrer to validate if page is accessed by navigation. UrlReferrer gets information about the URL of the client's previous request that linked to the current URL. for details visit this link
if(Request.UrlReferrer == null)
{
//code to redirection to login page
}

How can I handle forms authentication timeout exceptions in ASP.NET?

If the session has expired and the user clicks on a link to another webform, the asp.net authentication automatically redirect the user to the login page.
However, there are cases when the user does not click on links to other webforms. For example: edit link in gridviews, when using AutoCompleteExtender with textboxes and the application attempts to get the information, and basically, in every case when a postback is done and the event is not automatically handled by the asp.net authentication.
What is the best way to handle these exceptions?
UPDATE: I have just modified the question title: forms authentication timeout, instead of the initial session timeout. Thanks for making me aware of this difference.
UPDATE: I have just created a new question with the specific problem I am facing: How to handle exception due to expired authentication ticket using UpdatePanel?. Surprisingly, I have not found much information about it. I would really appreciate your help.
This is why many systems include timers on the page to give approximate timeout times. This is tough with interactive pages. You really need to hook ajax functions and look at the return status code, which is a bit difficult.
One alternative is to use code based on the following which runs early in the page lifecycle and perform an ajax redirect to a login page. Otherwise you are stuck trying to intercept the return code from ajax and in asp.net where the ajax is done 'for you' (ie not a more manual method like jQuery) you lose this ease of detection.
http://www.eggheadcafe.com/tutorials/aspnet/7262426f-3c65-4c90-b49c-106470f1d22a/build-an-aspnet-session-timeout-redirect-control.aspx
for a quick hack you can try it directly in pre_init
http://forums.asp.net/t/1193501.aspx
Edit
what is wanted are for forms auth timeouts, not session timeouts. Forms auth timeouts operate on a different scale than session timeouts. Session timeouts update with every request. Forms auth tickets aren't actually updated until half of the time goes by. So if you have timeouts set to an hour and send in one request 25 minutes into it, the session is reset to an hour timeout, the forms auth ticket isnt touched and expires in 35 minutes! To work around this, sync up the session timeout and the forms auth ticket. This way you can still just check session timeouts. If you don't like this then still - do the below and sync up the timeouts and then parse the auth ticket and read its timeout. You can do that using FormsAuthentication.Decrypt - see:
Read form authentication cookie from asp.net code behind
Note that this code requires that upon login you set some session value - in this case its "UniqueUserId". Also change the login page path below to fit yours.
protected void Application_PreRequestHandlerExecute(object sender, EventArgs e)
{
//Only access session state if it is available
if (Context.Handler is IRequiresSessionState || Context.Handler is IReadOnlySessionState)
{
//If we are authenticated AND we dont have a session here.. redirect to login page.
HttpCookie authenticationCookie = Request.Cookies[FormsAuthentication.FormsCookieName];
if (authenticationCookie != null)
{
FormsAuthenticationTicket authenticationTicket = FormsAuthentication.Decrypt(authenticationCookie.Value);
if (!authenticationTicket.Expired)
{
if (Session["UniqueUserId"] == null)
{
//This means for some reason the session expired before the authentication ticket. Force a login.
FormsAuthentication.SignOut();
Response.Redirect("Login.aspx", true);
return;
}
}
}
}
}
If you're using Forms Authentication, the user will be redirected to the login page when the Forms Authentication ticket expires, which is not the same as the Session expiring.
You could consider increasing the Forms Authentication timeout if appropriate. Even to the extent of using a persistent cookie. But if it does expire, there's no real alternative to redirecting to the login page - anything else would be insecure.
One way to deal with Session timeouts is to use Session as a cache - and persist anything important to a backing store such as a database. Then check before accessing anything in Session and refresh if necessary:
MyType MyObject
{
get
{
MyType myObject = Session["MySessionKey"] as MyType
if (myObject == null)
{
myObject = ... get data from a backing store
Session["MySessionKey"] = myObject;
}
return myObject;
}
set
{
Session["MySessionKey"] = value;
... and persist it to backing store if appropriate
}
}
If you're using a master page or a base page, I would add some logic to one of the events in the page lifecycle to check whether the session is new:
protected void Page_Load(object sender, EventArgs e)
{
if (Session.IsNewSession)
{
//do whatever you need to do
}
}

How to force the user to change his password after first login?

I want to force the user to change his password after his first login. Now, where should I put the redirection code to ChangePassword page ?
If I put it in the Page_Load of Default page, user can move to any page because he is Authenticated.
If I put it in the Page_Load of Master page, the ChangePassword page uses the same master page, and it'll enter in an infinit loop of redirections.
I though of ignoring the redirection if the Page is the ChagePassword page from the Master page, and I found this answer which says:
This sounds like a bad idea to start with. The idea of the master is that it shouldn't care what page is there as this is all common code for each page.
Any suggestion!
Here you are, a fully tested solution ;)
protected void LoginButton_Click(object sender, EventArgs e)
{
/****note: UserName and Password are textbox fields****/
if (Membership.ValidateUser(UserName.Text, Password.Text))
{
MembershipUser user = Membership.GetUser(UserName.Text);
if (user == null)
{
FailureText.Text = "Invalid username. Please try again.";
return;
}
if (user.IsLockedOut)
user.UnlockUser();
/* this is the interesting part for you */
if (user.LastPasswordChangedDate == user.CreationDate) //if true, that means user never changed their password before
{
//TODO: add your change password logic here
}
}
}
You can do it in GLobal.asax file.
Check if user in logged in and request url is not ChangePassword then redirect to change password page.
/// <summary>
/// this event occurs just after user is authenticated
/// </summary>
void Application_AuthorizeRequest(object sender, EventArgs e)
{
// check if user is authenticated
if (User.Identity.IsAuthenticated)
{
// checking page extension
switch (System.IO.Path.GetExtension(Context.Request.Url.AbsoluteUri.ToLower()))
{
case ".bmp":
case ".gif":
case ".jpg":
case ".jpe":
case ".jpeg":
case ".png":
case ".css":
case ".js":
case ".txt":
case ".swf":
// don't redirect, these requests may required in many cases
break;
default:
// checking if request is not for ChangePassword.aspx page
if (!Context.Request.Url.AbsoluteUri.ToLower().Contains("/changepassword.aspx"))
{
Context.Response.Redirect("~/ChangePassword.aspx");
}
break;
}
}
}
We had an app with similar requirements. We extended the base ASP.NET membership provider to allow for a check on the LastPasswordChangedDate and compared it to the CreateDate. If equal, that means the user has never changed their password, and was redirected to the login page.
I see you would like to have some kind of check to keep bugging them even after the login. I think you can accomplish this in the AuthorizationRequest of the Global.asax. That might be expensive though.
You may handle the following events of the Login control,
•LoggedIn
•LoggingIn
Good luck, I hope this helps.
as i understand you should put the validation code in "Page_PreRender"
protected void Page_PreRender(object sender, EventArgs e)
{
//Validation Code
}
this event will fire the code before the page renders anything
Which object are you putting into the section in order to evaluate if the user is authenticated? I would just set a boolean property named "ChangePasswordOnNextLoggin", then if its true I redirect to "ChangePassword.aspx", you may put it wherever you want (even in the master page, as you only redirect if this property is true, avoiding the infinite loop).
But personally I would make a wrapper for the PAGE object, that every .aspx code behind class should inherit, then I would inherit this wrapper instead, on the wrapper ctor I would add an Authenticate method to the Load event in such a way it would be the first method to be called when any page is loaded. If I do it, i'm able to avoid putting validation code on MasterPage and the code behind, making the code cleaner. Do you get it?
In the place of your code where the user is authenticated.
Since you want the user to change his password on the very first login, after registration, you just create one more field in your database's login table which will have a status value whether the initial pasword change process has been done. So when a user logs in the first time, that value is checked and, if it is something like "unchanged," redirect the user from the login page to the change password page. Upon successful password change, update the field.
In SQL Server 2005(plus VS2008), Apart from all the "add one more field" approaches, I think it's much easier to execute asp.net security database's built in stored procedure aspnet_Membership_FindUsersByName. It returns a dataset with all the info you'll ever need incl last activity date, last password change date, last login date etc with time values.

Forms Authentication and authentication cookie not persisting

aware that there are a lot of questions relating to Forms Authentication and the persistence of cookies, but having spent most of a day delving around, I'm still having difficulties.
My Problem
I am working on a web app (VS2010 but webapp is f/w 3.5) which restricts access to certain parts of the app to authenticated users (whereas other parts are open). My problem is that my authentication cookies do not appear to be persisting after I close the browser.
My Approach
I have written a simple login.aspx page which is configured in web.config as follows:
<authentication mode="Forms">
...and the individual pages' behaviour are declared like so:
<location path="ClientManageAccount.aspx">
<system.web>
<authorization>
<deny users="?" />
</authorization>
</system.web>
</location>
...which works fine in every respect EXCEPT for these cookie shenanigans...
I create the authentication cookie manually once I have authenticated my user's login & password against the database (which works fine) in the login.aspx page. If the user selects the 'keep me logged in' checkbox, the cookie is generated using this method:
private void GenerateAuthenticationCookie(int expiryInMinutes, Guid userGuid)
{
DateTime cookieExpiration = DateTime.Now.AddMinutes(expiryInMinutes); // change to months for production
var authenticationTicket =
new FormsAuthenticationTicket(
2,
userGuid.ToString(),
DateTime.Now,
cookieExpiration,
true,
string.Empty,
FormsAuthentication.FormsCookiePath);
// ticket must be encrypted
string encryptedTicket = FormsAuthentication.Encrypt(authenticationTicket);
// create cookie to contain encrypted auth ticket
var authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
authCookie.Expires = authenticationTicket.Expiration;
authCookie.Path = FormsAuthentication.FormsCookiePath;
// clear out existing cookie for good measure (probably overkill) then add
HttpContext.Current.Response.Cookies.Remove(FormsAuthentication.FormsCookieName);
HttpContext.Current.Response.Cookies.Add(authCookie);
}
The objective here is that I store a user Guid in the auth cookie, which I will then use to restore a user object into session (this is also in the login.aspx page, and my thinking is that I'd like to pluck the user guid from the auth cookie that I have created, and use it to stuff the corresponding user record into session and redirect to the requested page):
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
TryAutoLogin();
}
}
private void TryAutoLogin()
{
HttpCookie cookie = HttpContext.Current.Request.Cookies.Get(FormsAuthentication.FormsCookieName);
if (cookie != null)
{
FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(cookie.Value);
if (ticket != null)
{
if (ticket.Name.Length > 0)
{
try
{
Guid userGuid = new Guid(ticket.Name);
KUser user = UserFunctions.GetUserFromUserGuid(userGuid);
if (user != null) Session["User"] = user;
FormsAuthentication.RedirectFromLoginPage(userGuid.ToString(), true);
}
catch (Exception anyException)
{
// don't do anything for now - do something smart later :-) }
}
}
}
}
Finally, here is the code for the login button on my login.aspx page:
protected void Submit_OnClick(object sender, EventArgs e)
{
long userId = 0;
UserAuthenticationStatus status;
status = (UserAuthenticationStatus)UserFunctions.UserAuthenticates(EmailAddress.Text, Password.Text, ref userId);
switch (status)
{
case UserAuthenticationStatus.Authenticated:
//email address and password match, account ok, so log this user in
KUser user = UserFunctions.GetUser(userId);
Session["User"] = user;
if (ChkRememberMe.Checked)
{
GenerateAuthenticationCookie(15, user.UserGuid); // 15 minutes
FormsAuthentication.RedirectFromLoginPage(user.UserGuid.ToString(), true);
}
else
{
FormsAuthentication.RedirectFromLoginPage(user.UserGuid.ToString(), false);
}
break;
case UserAuthenticationStatus.AuthButLocked:
// email/pwd match but account is locked so do something
ShowLockedAccountMessage();
break;
case UserAuthenticationStatus.EmailFoundIncorrectPassword:
case UserAuthenticationStatus.EmailNotFound:
case UserAuthenticationStatus.Unknown:
// either the email wasn't found, or the password was incorrect or there was some other problem
// present message stating this and offer chance to register
ShowFailedLoginMessage();
break;
default:
ShowUnavailableMessage();
break;
}
}
As you can see, there's nothing particularly complex going on, but despite the fact that the authCookie which is created in GenerateAuthenticationCookie(..) being created correctly (as far as I can tell) it does not persist.
One thing I have noticed is that if I place some code into the Application_AuthenticateRequest method in global.asax.cs, such as:
protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
HttpCookie cookie = HttpContext.Current.Request.Cookies.Get(FormsAuthentication.FormsCookieName);
if (cookie != null)
{
int x = 4; // just a dummy line so that I can set a breakpoint
}
}
...that breakpoint is sometimes hit following a new browser session, although it stops being hit once I navigate away from the startup page (in this case a dummy start.aspx page used purely for dev & testing).
So, apologies for the long question, but I'm truly suffering here.
Things I have checked/tried
Ensuring that the code is being executed - YES
Browser settings - i.e. no deletion of cookies on exit - CONFIRMED NO DELETION
Trying different timeouts - e.g. equal or different to the web.config timeout, doesn't seem to matter...
...and of course at least twenty or thirty different previous questions, but to no avail.
System/Dev Environment
Windows 7 64-bit, VS2010 (but proj is a 3.5), SQL Server 2008 Express.
On my dev server, this problem remains so I'm not sure it's necessarily environmental - that machine is a WS2008R2 box running SQL 2008R2 - and the same problem remains.
Does anyone, anywhere, have any ideas for things I can try here? I have a hunch I could get this working by intercepting the initial Application_AuthenticateRequest hit in global.asax.cs and stuffing something into session state to mark as 'authenticated' (to avoid an expensive authentication attempt every time that method is called, which turns out to be several times per page.
Thanks in advance,
John
OK, having spent all that time writing that, I had a moment of clarity and realised that (a) I didn't need to be doing any of that checking on the Page_Load() as (if this were working properly) the login.aspx page wouldn't be called at all, and (b) I ought to have been able to get to the cookie from the Session_Start - which is where I relocated the TryAutoLogin code.
This in itself was a step forward, but despite retrieving the cookie and therefore the user guid from it, I found that by I was still getting punted back to the login.aspx page.
It was at this point I recalled the fact that I have a parent master page and two child master pages - one which I set for non-authentication pages (e.g. homepage) and one for those pages requiring authentication. I vaguely recalled a problem with session timeouts and had placed the following code in the OnInit override:
if (Session["User"] == null)
{
FormsAuthentication.SignOut();
FormsAuthentication.RedirectToLoginPage();
Response.End();
}
...which in itself wasn't so bad (and avoided a nasty bug on timeouts) but also on the start.aspx page, I found this gem:
Session.Clear();
...in the Page_Load!
So, what was happening was that I was inadvertently clearing the session into which I had placed my newly recovered user record. Which meant that the authorisation master page's OnInit override was then detecting the absence of the user object and - ta dah! - signing the user out, which in turn removes the authorisation cookie...
So, a bit of wiring and some sleuthing later, and I can put this one to bed.
Thanks for reading (even if I did figure it out on my own)... :)

Categories