I'm implementing some asp.net application in .NET Framework 1.1. Within that application I want to implement some security policy like as follows
When user login to the system, and copies the url and paste it into other browser, then that new browser should redirect to him on login page.
When user is browsing application, copy the current url, logout, paste the url to a new browser then he should be redirected to the login page.
Please help me implement this type of security in asp.net 1.1
You can set session variable on login page. Create one function "IsLoggedIn" and in this function check whether value is set for session or not. If not than user is not logged in and show login page. This function you need to copy on each page's page_load event. Make sure you reset session or make it null once user logs out.
public static bool IsLoggedIn()
{
if (System.Web.HttpContext.Current.Session["UserName"] != null && Convert.ToString(System.Web.HttpContext.Current.Session["UserName"]) != String.Empty)
{
return true;
}
else
{
return false;
}
}
if (!IsLoggedIn())
{
Server.HtmlEncode(Request.Url.ToString());
Response.Redirect("Login.aspx" + "?ReturnUrl=" + (Request.FilePath));
}
Related
If a user is authenticated, I want to take him to the "home" page but with a model that contains the user profile, otherwise, I want to post-back the same page with the model errors. Here's what I have done:
[HttpPost]
[AllowAnonymous]
public ActionResult Index(Login loginViewModel)
{
if (ModelState.IsValid)
{
IUserProfile userProfile = ValidateUser(loginViewModel);
if (userProfile != null)
{
FormsAuthentication.RedirectFromLoginPage(loginViewModel.UserName, loginViewModel.RememberMe);
// return View(userProfile); This obviously won't work
}
else
{
ModelState.AddModelError("InvalidCredentials", "Invalid password. Please try again.");
}
}
return View();
}
The problem is, how do I pass the view model (IUserProfile) to the Home/Index.cshtml view because I am not explicitly redirecting him to the home page; it is being done by the FormsAuthentication.RedirectFromLoginPage method.
I also cannot call a return View(userProfileViewModel) after the call to the FormsAuthentication.RedirectFromLoginPage because if I do, it will, by convention, try to create the view with the name Index on the Login controller and will try to pass it the UserProfile view model, which is wrong and will result in an exception.
You need to pass the model in your Index action in the Home controller.
Indeed the RedirectFromLoginPage will only send an HTTP status code (302) to the browser telling it to redirect to the new page and then calling the desired action. it is in this action (in your case Index in Home) that you have to pass your view model.
First of all you action should do one thing and one thing only... and not two. You want to use Index as login and as home page. Why don't you separate Login logic from home page logic? When you authenticate a user redirect him/her to Home/Index at that point, and if login fails show Login again. Next, instead of loading user profile during login authentication, do this when you redirect user to their home page (home page being my logic here). Once you reach the page, load their profile and cache it in some way either through session or some other mechanism.
In addition to this, why don't you use FormsAuthetnication.SetAuthCookie(username, rememberMe) instead of FormsAuthentication.RedirectFromLoginPage. Once a cookie is created call return RedirectToAction("Index", "Home"). In this action you can use HttpContext.Current.User.Identity.Name to read the username and pass it to your method to load the profile.
Try this
if (Session["SessionName"].ToString() != "Role")
{
return RedirectToAction("UnAuthorised", "Login");
}
Use this code in your index page
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;
}
}