I'm trying to add username to cookie and clear it on logouts but Request.IsAuthenticated returns always true so I'm not able to know if it is a member or not on the next page.
Here is what I'm trying:
public void Logout()
{
FormsAuthentication.SignOut();
Session.Abandon(); // trying everything...
}
protected void signin_submit_Click(object sender, EventArgs e)
{
//checklogins...
HttpCookie authCookie = FormsAuthentication.GetAuthCookie(username_top.Text, true);
}
I'm clicking the Logout from javascript function, and it hits the debugger so I'm sure that its being called.
I'm checking the value on Page_Load:
protected void Page_Load(object sender, EventArgs e)
{
bool isAuth = Request.IsAuthenticated; // always true !!!
if (isAuth)
{
registeredDiv.Visible = true;
guestDiv.Visible = false;
}
}
What am I missing? How can I know if the user is logged in or not?
Edit: I found out that authenticationMode was set to Windows in web.config.
Edited it as:
<authentication mode="Forms">
But now it always returns false. I tried redirecting after login to same page yet still didn't work. Any ideas?
When you say that you are hitting the debugger and making the call through Javascript, are you doing this via ajax? I'm wondering that you are indeed signing out, but not redirecting the user, which means that the cookie the user has on there machine is not being overwritten/destroyed so that when they next request a page, it works again because the cookie still exists.
When the user hits your logout button on your site, you really need to have them redirect to a new page so that the cookies can be set (or unset as it were) properly...Here's the MSDN Article on Forms Authentication Signout and its example code calls RedirectToLoginPage() which will sort out the cookies as previously mentioned.
I've found FireCookie for Firebug really helpful in debugging cookie related issues.
Edit
According to the MSDN article I linked to:
You can use the SignOut method in
conjunction with the
RedirectToLoginPage method to log one
user out and allow a different user to
log in.
Your code does not have RedirectToLoginPage called, so just calling FormsAuthentication.SignOut() isn't enough (unless you are going to manually do the work of RedirectToLoginPage)
Edit 2
Perhaps change your Sign In Button code to use this function instead:
FormsAuthentication.RedirectFromLoginPage(username_top.Text, true)
As this will automatically take care of setting all the cookie stuff...
Edit 3
Glad you sorted it out, The above function (edit 2) would have just done what you said you had missed out on (adding the cookie to the response)...
Related
I have a site with multiple pages, not necessarily heirarchical. I want to query the user's identity (using AD...) whenever the user first enters the site, and create session state variables for the convenience of other pages as needed. A user could possibly enter the site without going through the default.aspx page, so I thought I'd put the code in the Master Page's code-behind.
On the assumption this is a good idea, versus some sort of static class that maintains this information, I started setting it up, but found the Master Page code-behind doesn't always seem to get fired when I enter the site. Is this a debugging phenomenon, or am I right, and the Master Page is the wrong place to put this code...?
I would recommend using the Global.asax class. You'll need to add it to your web app if it's not already there. Once you have it, you can then use the various events (session start and end, app start and end and error) to implement business logic particular to what you need exactly.
I tend to monkey around with the logged in user in the Application_PreRequestHandlerExecute event of the global.asax. This will allow you to look at the User Principle (eg - User.Identity.Name) to see who is logged in (or if they're not logged in) and do what you need to (such as set Session information for the user, etc.).
Here's a tidbit of code I've got on one .NET web app that uses the Global.asax for storing user data in the Session.
protected void Application_PreRequestHandlerExecute(Object sender, EventArgs e) {
if (Context.Handler is IRequiresSessionState || Context.Handler is IReadOnlySessionState) {
SetUserItem();
}
}
private void SetUserItem() {
if (Session["UserItem"] == null)
Server.Execute("~/SetSessionUserObj.aspx", true);
}
... and then the SetSessionUserObj.aspx.cs
protected void Page_Load(object sender, EventArgs e) {
string ID = User.Identity.Name;
MyUser myUser = new MyUser();
UserItem userItem = myUser.GetUserItemByID(ID);
if (userItem != null) {
Session["UserItem"] = userItem;
}
}
This is just one manner that you can go about accessing a user's identity in the global.asax. You don't necessarily have to go about doing a Server.Execute to set user data (I just did it for other reasons that fall outside the scope of this question).
Good luck.
I am using asp.net membership and I got some code from code plex
on loin page that is common to all role members I am doing following code:
protected void Login1_Authenticate(object sender, AuthenticateEventArgs e)
{
//some code missing
below is to identify role and then redirecting to appropriate default page
else
{
// Next, determine if the user's username/password are valid
if (Membership.ValidateUser(loginUsername, loginPassword))
{
e.Authenticated = true;
string[] userRoles = Roles.GetRolesForUser(loginUsername);
switch (userRoles[0])
{
case "Administrator":
Login1.DestinationPageUrl = "~/Admin/Default.aspx";
break;
case "Member":
Login1.DestinationPageUrl = "~/Members/Default.aspx";
break;
}
}
}
But when I log out, it logs out properly, redirecting me to the log out page but attached a return url:
http://localhost:52045/NexLev/login.aspx?ReturnUrl=%2fNexLev%2fMembers%2fDefault.aspx
So if first time a member log ins then it takes to correct page then if it log out then the above url apear on log out page, but next time if an admin logs in then it take to the LoginView logged in template kept on the same log in page instead of taking it to the default page of admin.
Could some body suggest how to overcome with this problem? Or should I apply a different approach to redirect according to user roles.
Instead of setting DestinationPageUrl dependent on the role, you can use a common default page for all users (members as well as administrators). After a user logs in he is then redirected to the common default page and all that page does is check the role of the user and then redirect the user to the right page using Response.Redirect.
In the Login1_LoggedIn event try
Response.Redirect(Login1.DestinationPageUrl);
This will force LoggedIn event to redirect to the DestinationPageUrl page.
Alternate Title: How to redirect on session timeout
FINAL SOLUTION: Credit to: Robin Day (Although I tested Ben's solution and it also works and the other two solutions are also both good solutions)
I got rid of the basepage that I had originally.
Put this in the Session_Start of Global.asax
void Session_Start(object sender, EventArgs e)
{
string cookie = Request.Headers["Cookie"];
// Code that runs when a new session is started
if ((null != cookie) && (cookie.IndexOf("ASP.NET_SessionId") >= 0))//&& !Request.QueryString["timeout"].ToString().Equals("yes"))
{
if(Request.QueryString["timeout"] == null || !Request.QueryString["timeout"].ToString().Equals("yes"))
Response.Redirect("Default.aspx?timeout=yes");
}
}
Put this on the Defualt.aspx page:
if (!IsPostBack)
{
if (Request.QueryString["timeout"] != null && Request.QueryString["timeout"].ToString().Equals("yes"))
{
Response.Write("<script>" +
"alert('Your Session has Timedout due to Inactivity');" +
"location.href='Default.aspx';" +
"</script>");
}
}
This solution works even when the timeout occurs on the Default.aspx page
END SOLUTION
I have a base page that checks for session timeout. (thats all it does). I want to redirect to the home page if there is a session timeout. However, the home page also inherits from this base page.
I'm not sure if i'm explaining this well:
Step 1: One of my pages loads
Step 2: It sits for more than 20 minutes(this would cause session timeout).
Step 3: I click on something that causes poastback
Step 4: Basepage detects timeout and redirects to default.aspx
Step 5: As default.aspx loads, the basepage detects that there is still a timeout and once again tries to redirect to default.aspx.
Step 6: Repeat step 5
The bold is the undesired effect...
This is the basepage code.
using System;
using System.Web.UI;
public class SessionCheck : System.Web.UI.Page
{
public SessionCheck() {}
override protected void OnInit(EventArgs e)
{
base.OnInit(e);
if (Context.Session != null)
{
//check the IsNewSession value, this will tell us if the session has been reset.
//IsNewSession will also let us know if the users session has timed out
if (Session.IsNewSession)
{
//now we know it's a new session, so we check to see if a cookie is present
string cookie = Request.Headers["Cookie"];
//now we determine if there is a cookie does it contains what we're looking for
if ((null != cookie) && (cookie.IndexOf("ASP.NET_SessionId") >= 0))
{
//since it's a new session but a ASP.Net cookie exist we know
//the session has expired so we need to redirect them
Response.Redirect("Default.aspx?timeout=yes&success=no");
}
}
}
}
}
Thanks!!!
(If you need further clarification please ask)
Note: I know that if I redirect to a page that does not inherit from this basepage it would fix the problem. But i don't like this solution.
Can you use the event Session_OnStart within the Global.asax?
This will be fired once whenever a new session begins. You can do your redirect in there.
The key I guess though is that you only redirect to the home page if you're not already on it. You can do this by just checking the URL in the Request object.
We had similar situation. We first check if the there's Session Timeout and within that we only redirect if current page is not the Default Login page.
The below will do the trick with your existing code but robin day's sugestion of using global.asax is a better option.
if (Context.Session != null)
{
//check the IsNewSession value, this will tell us if the session has been reset.
//IsNewSession will also let us know if the users session has timed out
if (Session.IsNewSession)
{
//now we know it's a new session, so we check to see if a cookie is present
string cookie = Request.Headers["Cookie"];
//now we determine if there is a cookie does it contains what we're looking for
if ((null != cookie) && (cookie.IndexOf("ASP.NET_SessionId") >= 0))
{
//since it's a new session but a ASP.Net cookie exist we know
//the session has expired so we need to redirect them
//Only redirect if the current page is NOT Default.aspx
if (Request.Path.Substring(Request.Path.LastIndexOf("/")) != "/Default.aspx")
{
Response.Redirect("Default.aspx?timeout=yes&success=no");
}
else if (Request.QueryString["timeout"] == "yes")
{
ScriptManager.RegisterStartupScript(this, this.GetType(), "TimeOutScript", "alert('Your session timed out');", true);
}
}
}
}
Editing the answer to respond to comments below becuase it is easier than adding more comments:
I did not provide you with a solution to redirect when the session timed out, you simply cannot do that, the session has timed out, there is nothing to redirect. You said "i just wanna know if there was a timeout" and i gave you a solution for that. There is no real way to tell if a user is hitting page x becuase their session has timed out or because they have opened a browser and started a new session, all you know is there is no existing session. If they hit a page they need to be authenticated to view then you can assume the session has timed out because they should not be hitting the page from scratch. But you can't do this on the home page becuase you can't tell the difference between a user who's session timed out on this page and a user who is just hitting the page for the first time. I have updated the code so that for every page other than Default.aspx it will redirect, and if it has redirected to Default.aspx due to a session time out it will pop up a javascript alert.
Create a common base page that contains all things you want to have both in your home page and in other pages.
Than inherit from this your home page and another base page (say SessionCheck) in which to put your session expiration logic. All your pages but home have than to inherit from SessionCheck page.
public class BasePage: System.Web.UI.Page //(this contains all things shared between all pages)
public class SessionCheck : BasePage //(your session loginc in this class)
public class Home : BasePage
Put a property in your base page:
public bool IsDefault { get; set; }
In the PreInit event of your default page:
public void Default_PreInit(object sender, System.EventArgs e)
{
this.IsDefault = true;
}
Modify your session check:
if (Context.Session != null && !this.IsDefault)
{
// blibbitty blah blah
}
In one of the ASP.NET MVC apps we would like to logoff the user automatically if he closes the browser tab in which the app is opened.
We are using the following code when he authenticates.
FormsAuthentication.SetAuthCookie(userName, false)
As of now, if we closes the browser window and relaunch it, users are asked to authenticate again. But we want to ask users to authenticate again if they close the tab and try to access any of the website urls.
We decided to use cookie less authentication so that the authentication token is part of the url. When the tab is closed and they open the website again, they will be asked to authenticate again :)
I have not tried this myself, but I think the following approach should work:
On the client side, you can use the OnUnload event of your document to launch a javascript function that would call your server-side signout method via ajax.
On the server side, you should have the action method call FormsAuthentication.SignOut() and Session.Abandon();
A browser clears all Session scoped objects only when it is completely closed, and not when an individual tab is closed.
One way could be to use a very low Session timeout and have a server-side script poll every few seconds to hit an object on the page. This will extend Session time again. So if a tab is closed, the script can't find the object thereby allowing the Session to timeout. One problem here is if your app is on a pretty high load, your app could DoS itself!
Actually there is no way we can LogOff the user when the user closes the browser tab. The only way for this is to check if the the user is authenticated when we call the LogOn method in the Controller.
This code is an example of how I do it in ASP.Net MVC 3.
public ActionResult LogOn()
{
if (Request.IsAuthenticated)
{
FormsAuthentication.SignOut();
return RedirectToAction("Index","ProductManager");
}
return View();
}
You can simply use session variables to automatically log off anybody trying to return to the secured destination page. Create a single session variable (integer or boolean) and in the onclick event of your login button reset it to a known state after acknowledging that the user has a valid credential then set or increment that session variable in the page_load event of the page your trying to secure. Test these values and signout the user if he is trying to return to the page or do nothing if otherwise. The code may look similar to this.
protected void btnLogin_Click(object sender, EventArgs e)
{
if (IsAuthenticated == true)
Session["IsUserLoggedIn"] = (int)0;
}
protected void Page_Load(object sender, EventArgs e)
{
if (HttpContext.Current.User.Identity.IsAuthenticated == true)
{
if (Session["IsUserLoggedIn"] != null)
{
int IsUserLoggedIn = (int)Session["IsUserLoggedIn"];
if (IsUserLoggedIn <= 0)
{
Session["IsUserLoggedIn"] = (int)IsUserLoggedIn + 1;
}
else
{
Session["IsUserLoggedIn"] = (int)0;
FormsAuthentication.SignOut();
FormsAuthentication.RedirectToLoginPage();
}
}
}
else { Session["IsUserLoggedIn"] = (int)0; }
}
simple question...
Given I have an ASP.NET site, which uses a [custom] RoleProvider,
Is there any way in which I can somehow "refresh" the provider without forcing the user to log out of the site and log back in?
I'm looking for something that would be akin to a fictional method
Roles.Refresh()
Specifically, I am looking at this for if an administrator changes a user's roles, the user sessions could maybe refresh themselves every 10 minutes or something.
I assume you have something like this in your web.config:
<roleManager enabled="true" defaultProvider="..."
cacheRolesInCookie="true">
The roles are cached in a cookie , so you can force them to refresh by deleting the cookie. This method worked for me. I added the cookieName attribute so that I don't rely on asp.net's default. For your scenario, though, you may be able to just set the cookieTimeout attribute to something reasonable and be done with it.
This method won't update the roles immediately, of course. They will be updated on the next page load after you delete the cookie.
Refresh just need to delete the cookie:
For C#: Roles.DeleteCookie(); // Works as Roles.Refresh()
If you don't want to use cookies you can use Session object to cache the roles.
like this:
public override string[] GetRolesForUser(string username)
{
System.Web.SessionState.HttpSessionState Session = HttpContext.Current.Session;
if (Session["roles"] == null)
Session["roles"] = MyDataProvider.Security.GetRolesForUser(username);
return (string[])Session["roles"];
}
When you need to update the roles for this user you can do
Session["roles"] = null
depend on the custom role provider used.
Just call a "update my role" function on every request? (bad way but at least your sure to update it)
The roles are cached in a cookie (encrypted of course). The simplest solution will be to disable caching in the web.config file. You will loose some performance.
Else you must somehow resend the auth cookie. One major problem is that many browsers will not accept cookies on redirects with method post.
The other solution that worked for me:
1) In a aspx methodod log the user out and store the username in the session
//Add User to role reviewer and refresh ticket
Roles.AddUserToRole(User.Identity.Name, Constants.ROLE_REVISOR);
FormsAuthentication.SignOut();
FormsAuthentication.SetAuthCookie(User.Identity.Name, false); //Might work in some browsers
Session["REFRESHROLES"] = User.Identity.Name;
Response.Redirect("someprotectedurl?someid=" + someid);
2) In the loginpage sign the user in again if username is stored in session
protected void Page_Load(object sender, EventArgs e)
{
string returnUrl = Request.QueryString["ReturnUrl"];
if(String.IsNullOrEmpty(returnUrl) == false)
{
if(Session["REFRESHROLES"] != null)
{
if(!string.IsNullOrEmpty(Session["REFRESHROLES"].ToString()))
{
FormsAuthentication.SetAuthCookie(Session["REFRESHROLES"].ToString(), false);
Session.Remove("REFRESHROLES");
Response.Redirect(returnUrl);
return;
}
}