Set global variables to client only asp.net - asp.net

A while back I created a simple login form, which went to a database and pull down the information of the users logging on. Now I did this by using global variables; not realizing that they are server side variables not client side. So what happening is, say if I logged on on one computer, all other users using that site would be logged on as me.
So my question is.
A) Is there a way to set the global variable to client side, so that
only the people using that pc are affected by the change in variables.
B) Is there an alternatve to using global variables; so that i can
pass data between pages, like the global variable does.
I have tried using query strings. And although they work. They are a slight bit fiddly i find, as you have to parse them, and every time you leave each page; you have to send them to the new page.

I think ASP.NET session state will suit your needs pretty well. Another way is to use cookies and it might be a better solution if you need to persist information for a given user across his browser sessions. But please note that cookies shouldn't be used for storing sensitive information (like passwords).

Create a class that holds all the user information that you retrieved from the database when the user logged in:
public class User {
public string Name {get; set;}
public int Id {get; set;}
}
Create a Session-level property that accesses the User property. This property should exist on each page that references the User object. Alternatively, you can create a base page that contains this property.
public User CurrentUser
{
get {
if(Session["User"] == null)
return null;
return (User)Session["User"];
}
set {
Session["User"] = value
}
}
Now, each time you reference this property, you just need to check if the object is null. If it is null, there is no logged-in user:
if(this.CurrentUser == null) {
//no logged-in user
}
else {
//the user is logged in
}

Related

How can i do custom authorization in my ASP.NET MVC application

I am making a small SAAS application. I am using the same database for all users and only differentiating between the data using username and ids. This means that the user can type in a new url in the browser and see other users data. This, of course is not a desirable approach. I would like to do a check to see if the current user can actually access the resources: eg.
http://myapplication.com/images/15
And if the user changes the url to
http://myapplication.com/images/16
I should do a check in my database to see if the current user actually has access to see the images with user id 16. And if not redirect to a "not authorized" page.
How do I implement this?
The first step is to make sure that you never have any ID's for the user itself in the url. For instance, never have http://example.com/?user=10. You should always get the users id from their authentication rather than from the URL (or posted values either).
The second step, is to use that ID in your queries. So, for instance, let's say they seek http://example.com/images/100, then in your database you should have a mechanism that links the asset's ownership to the user, either a userid or a mapping table of id's to asset's, etc.. This way, if the user isn't allowed access, it will just return an empty result set. It's impossible for the data to be returned, and the empty result set should tell your page that the item doesn't exist (not necessarily an authorization failure, just that the object doesn't exist).
Third, any pages which are inherently about the user, such as a user profile, account page, or dashboard should never have any ID's at all in the URL, it should just automatically go to the authenticated users page.
Finally, if you need to prevent the user from accessing an entire page or set of pages, then you should do this in the OnAuthorization event or similar (custom attribute, base class, etc..) or using the built-in attribute authorization and use role based authorization. Never do authorization in the PageLoad or similar event (such as the controller action), because by the time you get to that step a lot of work has already happened in the pipeline. It's best to block access long before the page even starts to setup. Authorization events happen at the very beginning of the pipeline.
Make an Action that check userId and returns error page or file
public FileResult Image(string imageName)
{
string UserId = MethodWhereYouGetCurrentUserID();
if(imageName == null) return View("~/Views/Shared/Error.cshtml", (object)"Null image");
string imageShortName = imageName.Split(".")[0];
if(!UserId == imageShortName) return View(~/Views/Shared/Error.cshtml, (object)"You can't access to this");
string path = Server.MapPath("~/Contant/images/"+imageName);
return File(path, "image/jpg");
}
RouteConfig file
public static void RegisterRoutes(RouteCollection routes)
{
routes.MapRoute
(
name: "ImageRoute",
url: "/images/imageName",
default: new {controller = "Home", action = "GetImage"}
);
}

Is it alright to put sensitive data into the cache? ASP MVC

I currently implemented some "checkers" for my MVC application.
So far here is what i have,
Authorization(Form)
Authentication (Custom RoleProvider)
Action Filters(to make sure that the user won't put any bogus id numbers or try accessing the other's data by editing the GET url.
I have several questions regarding the best practices for cache on ASP MVC.
Here is my implementation of my login:
[HttpGet]
[ActionName("login")]
public ActionResult login_load()
{
return View();
}
[HttpPost]
[ActionName("login")]
public ActionResult login_post(string uname,string pword)
{
using (EmployeeContext emp = new EmployeeContext())
{
//h student log = new student();
int success = emp.login.Where(x => x.username == uname && x.password == pword).Count();
if (success == 1)
{
int id = (from logs in emp.login
join rol in emp.roles on logs.role equals rol.id
where logs.username == uname
select logs.id).First();
FormsAuthentication.SetAuthCookie(uname, false);
HttpRuntime.Cache.Insert("id", id);
return RedirectToAction("Details", "Enrollment", new { id = id});
}
return View();
}
}
(I plan on implementing H&S as soon)
Anyway, here are my concerns so far:
For security concerns, would it be fine to store something like id's on cache? or it's better if i use sessions ?
Let's say i successfully logged in, and i add another line of this code :
HttpRuntime.Cache.Insert("id", id);
Is it going to edit my previous record or it's going to add another entry?
I have this code from my Custom RoleProvider, HttpRuntime.Cache.Insert(cacheKey, roles, null, DateTime.Now.AddMinutes(_cacheTimeoutInMinute), Cache.NoSlidingExpiration); and i believe that they are "fired" everytime i ask a controller with a protection of [Authorize(Role="users")]. So does it make a new entry or it edits the previous/existing one?
Should i worry about deleting/clearing my cache as soon as the user decided to log out? my role provider timeout is currently set to 20 minutes
I need the id because aside from the username, it is my unique identifier and i use it to compare on whatever id the user is trying to access.
I am thinking if it would be possible to edit the cache and use it against my application.
Don't worry about storing the ID, you need to go back and refactor to use the inbuilt identity stuff that's in the box for MVC. Looking at your code I can only assume that this system would store passwords in plain text. You will not pass any compliance with a system like this.
Rule of thumb when it comes to "is this secure" is don't write it yourself. Find a proven product and use that.
If for whatever reason the inbuilt identity system that is provided with MVC doesn't work for your requirements, have a look into this: https://github.com/brockallen/BrockAllen.MembershipReboot
FYI:
Identity system is the service that logs people in, out and manages the logged in user. Feel free to head over to this to learn more about the inbuilt system for MVC: http://www.asp.net/identity/overview/getting-started/introduction-to-aspnet-identity
For security concerns, would it be fine to store something like id's on cache? or it's better if i use sessions ?
In this case it doesn't make a lot of difference. However, the cache cannot be distributed across multiple web servers. Session state can by changing the <sessionState> section of the web.config file. So you are building an inherent limitation in scalability into your application by using cache.
Let's say i successfully logged in, and i add another line of this code :
HttpRuntime.Cache.Insert("id", id);
Is it going to edit my previous record or it's going to add another entry? I have this code from my Custom RoleProvider, HttpRuntime.Cache.Insert(cacheKey, roles, null, DateTime.Now.AddMinutes(_cacheTimeoutInMinute), Cache.NoSlidingExpiration); and i believe that they are "fired" everytime i ask a controller with a protection of [Authorize(Role="users")]. So does it make a new entry or it edits the previous/existing one?
First of all, you have a major flaw in your code. Cache is intended to be shared between all users on the site. So, when you insert a value, such as HttpRuntime.Cache.Insert("id", id);, all of the users will see it. If you are using this value to lookup data later, then the user data will always be for the last user that signed in.
You can fix this by adding adding a value unique to the user to the key.
var key = this.User.Identity.Name + "|Id";
HttpRuntime.Cache.Insert(key, id);
Note I am using a pipe character as a separator here. This is assuming the user name doesn't allow a pipe character (which you would also need to ensure).
Secondly, using a proper cache pattern means that you will never need to worry about whether "id" exists because you have already made that check. Using the cache typically looks like this.
public static string GetUserID()
{
// Check whether the user is logged in
if (!HttpContext.Current.User.Identity.IsAuthenticated) {
return 0;
}
// Make a UNIQUE key that can be used for this scenario
var userName = HttpContext.Current.User.Identity.Name;
var key = userName + "|Id";
// Attempt to get the ID from the cache
var id = HttpRuntime.Cache[key];
// A null value indicates there was no value in the cache
if (id == null)
{
// No ID in the cache, look it up from the database
using (EmployeeContext emp = new EmployeeContext())
{
id = (from user in emp.login
where user.username = userName
select user.id).First();
}
// Store the ID from the database into the cache
HttpRuntime.Cache.Insert(key, id,
// No Dependencies
null,
// No absolute expiration (mimic the behavior of forms authentication)
System.Web.Caching.Cache.NoAbsoluteExpiration,
// Timeout 20 minutes after the last access
// (to mimic the behavior of forms authentication)
new TimeSpan(0, 20, 0),
// Setting to NotRemovable ensures that if the
// application pool restarts, you don't lose your cache
System.Web.Caching.CacheItemPriority.NotRemovable,
// No callback needed here
null);
}
return (string)id
}
Of course, you can improve performance if the value is available at login by inserting it into the cache directly, but you need to ensure you use the same key in that case.
Session is probably a better choice in this scenario, but either way you should make use of this pattern to double check you have a value before returning it to the user.
Should i worry about deleting/clearing my cache as soon as the user decided to log out? my role provider timeout is currently set to 20 minutes
If you use Session state instead of cache this is much easier. Simply call Session.Abandon() when the user logs out.

Session ASP.NET

Session question in asp.net/c#
I have multiple asp.net pages and a class object.
e.g.
Class User object contains
public string Name { set; get; }
public string Address { set; get; }
etc.....
pg1.aspx: when button is clicked, the data is stored in the session and redirects to pg2.aspx
e.g. pg1.aspx
User u = new User();
u.Name = TextBox1.Text;
Session.Add("USERINFO", u);
Response.Redirect("pg2.aspx");
e.g. pg2.aspx //reading the data..
User u = ((User)Session["USERINFO"]);
Response.Write(u.Name + "<br/>");
..etc.. ( I have 5 pages and the data is passed around from page to page in a session) once the user reaches the last page it stores in the database otherwise I dont want to store incomplete data in the database.
It all works fine except if I use multiple tabs to run same web app, the data overwrites eachother... It works fine if I use separate browsers, but not with tabs...
How can I avoid a user to enter the data in tab1 get to page 3 and if the user opens tab2 and continues not to over the data was entered in tab1....
I hope it makes sense... what I am trying to accomplish... Thank you.
This is probably a duplicate question, so I'll simply redirect you to some answers that would solve your problem.
asp.net - session - multiple browser tabs - different sessions?
Unfortunately, the accepted answer won't work since it maintains a "unique" session identifier for each page, not your group of 5 pages.
Your browser version and the different methods of launching new tabs and windows in it determines whether sessions are shared across multiple tabs and windows. Controlling it could be done with
The modification to web.config as described in the linked article
Coming up with a unique session key prefix for each session value
Using some logic to prevent the same user from opening multiple sessions on the same machine
The simplest way to work around your current implementation would likely be to check whether or not you have the information you would expect from that page, and if the conditions aren't met then require the data to be input, or redirect appropriately depending on which stage in the process you are (based on the data that is available).
So, as well as adding to the session, you can get:
var value = Session[key] as string;
if (value != null)
{
//move on to the next appropriate page
//after determining which that is by other conditions
}
//we obviously need the page at which we get this data!
And you can build upon your conditions from there

Where to store currently selected item id?

I'm trying to write an asp.net app which searches a sql db and returns/updates the data.
I want to be able to hold the currently selected id of the item my user has selected. For example a doctors surgery would select a patient record then be able to browse the app without having to re-select that patient on each page.
What would be the best way to do this. Ideally I need to be able to get this ID application wide. the only thing i can think of is to create a public class, store the id and make it public but this seems quite messy
Thank you
Store it in a Cookie or a Session variable.
Cookie info
http://msdn.microsoft.com/en-us/library/ms178194.aspx
Session Info
http://msdn.microsoft.com/en-us/library/ms972429.aspx
I would recommend storing it in a session variable:
Page.Session["CurrentPatient"] = YourPatient record
To get the record you would use:
YourPatientRecord = Page.Session["CurrentPatient"] as PatientRecord;
To make things easier I usually create a property in the page or base page to use throughout the system.
eg:
protected PatientRecord CurrentPatient
{
get
{
return Session["CurrentPatient"] as PatientRecord;
}
set
{
Session["CurrentPatient"] = value;
}
}
Then to use it in the page it would simply be:
PatientRecord oPatientRecord = this.CurrentPatient;

Asp.net, where to store the username of logged in user?

When a user log into my asp.net site I use the following code:
FormsAuthentication.RedirectFromLoginPage(userid, false);
As I often need to use the userid I can then later get the userid by:
string userid = System.Web.HttpContext.Current.User.Identity.Name;
Now I also want to show the logged in username on each page and my questions is therefore where do I place the username best if I need to use it on every page. User.Identity.Name is already taken by the userid so I can't use that one. Another solution would be to get the username from the database on each page, but that seems like a bad solution.
So: Is the best way to use Sessions to store the username?
There are essentially 6 different ways to store information, each with it's own benefits and drawbacks.
Class member variables. These are only good for the life of one page refresh.
HttpContext variables. Like class member variables, only good for one page refresh.
ViewState, these are passed from page to page to keep state, but increase the size of the downloaded data. Also, not good for sensitive information as it can be decoded.
Cookies. Sent on each page request. Also not good for sensitive information, even encrypted.
Session. Not passed to the end user, so good for sensitive information, but it increases the resource usage of the page, so minimizing usage for busy sites is important.
Authentication Cookie User Data - This is like like cookies, but can be decoded with the authentication data and used to create a custom IIdentity provider that implements your desired Identity information, such as Name or other profile information. The size is limited, however.
You can store just about anything in SessionState in asp.net. Just be careful and store the right things in the right places (you can also use ViewState to store variables.
Check this out for how to use SessionState to store and retrieve variables across postbacks.
public string currentUser
{
get { return Session["currentUser"] as string; }
private set { Session["currentUser"] = value; }
}
Using sessions isn't a bad idea but make sure to check for NULL when retrieving the values for when the sessions time out.
Or you could pass the variable through in the URL e.g
/Set
Response.Redirect("Webform2.aspx?Username=" + this.txtUsername.Text);
/Read
this.txtBox1.Text = Request.QueryString["Username"];

Resources