Setting unique Session variables at Application level - c#

I have a Web Forms application that does not have a login page. Technically a user can access any page directly. However, I need to be able to identify who the logged-in user is on each page. I don't want to add code to each page. I would rather set a unique session variable at the start of the session. For this I added into my Global.asax.cs the following:
protected void Session_Start(object sender, EventArgs e)
{
if (Session["LoggedInUser"] == null)
{
string networkId = HttpContext.Current.User.Identity.Name;
using (UnitOfWork unit = new UnitOfWork())
{
if (networkId.IndexOf("HLM\\") > -1) { networkId = networkId.Substring(4, networkId.Length - 4); }
loggedInUser = unit.PersonRepository.GetByNetworkID(networkId);
Session["LoggedInUser"] = loggedInUser;
}
}
else
{
loggedInUser = (Person)Session["LoggedInUser"];
}
}
I now see that it sets the loggedInUser to whatever user last created a session. Meaning, if Mike goes to the site he will see data that represents him as the loggedInUser. However, if Kate goes to the site after him, Mike will now see Kate's data. Basically, the last one in overwrites everyone's settings and Session_Start is overwriting the value for loggedInUser for all active Sessions.
Based on this link: https://books.google.com/books?id=nQkyi4i0te0C&pg=PA202&lpg=PA202&dq=C%23+set+unique+session+variable+in+global.asax&source=bl&ots=GV9nlEUzE5&sig=E4TT3NDbjp1GwEehgU3pLXKdvr0&hl=en&sa=X&ved=0ahUKEwiU9f322tvSAhVF7yYKHYaXCtwQ6AEITzAI#v=onepage&q=C%23%20set%20unique%20session%20variable%20in%20global.asax&f=false
It reads that I should be able to set unique session variables for each new session but my results don't show that.
Am I misunderstanding how this works? I need to set a unique session value at the beginning of each session for each user.

I found the issue. The Session_Start is doing what is supposed to at a unique session level. The way I was referencing the session value was all wrong. Instead of accessing the session value I was actually doing:
Person loggedInUser = Global.loggedInUser;
Which makes sense that it was returning the latest user to start a session.

Related

Save and retrieve Wrong Value From Json Object Items to IShared Preference in Xamarin.Android (Always Returns Logout Value)

I am developing a login application which save username and password using Shared Preferences in Xamarin Android (C#). Firstly, I get the username and password value from web service and then I check the value. If in my local db (sqlite) doesn't have the value so, I update the data with the newest one from web service. After that, I store the user ID by using my custom sqlite function to get the user ID with username and password.
So far, I can parse the Json Object from my web service and assign them into variables. But, I found something strange that, my parsed json object item can't be saved in my shared preferences. I've been 3 days searching and researching from internet but, I didn't find anything. I almost give up, guys. Would you like to help me? I would appreciate the helps.
Here what I did to my app.
I made utilities folder which save my essentials class. I made LoginSession class which save property of user now.
in my main activity
private void MyBtnLogin(object aSender, System.EventArgs e)
{
try
{
System.Net.Http.HttpClient client= new System.Net.Http.HttpClient();
System.Threading.Tasks.Task.Run(async () =>
{
string response = await _httpClient.GetStringAsync($"http://yourjson.com/{fix_email_value}");
JObject parsedObject = JObject.Parse(response);
int userID = parsedObject .Value<int>("ID");
string userEmail = _parsedResponseObject.Value<string>("Email");
string userPassword = _parsedResponseObject.Value<string>("Password");
List<User> lists= User.GetUserList(userID);
User updatedvalue= (from a in lists where a.Email == userEmail && a.Password == userPassword select a).FirstOrDefault();
if (updatedvalue== null)
{
updatedvalue= new User();
updatedvalue.ID = userID;
updatedvalue.Email = userEmail;
updatedvalue.Password = userPassword;
updatedvalue.StoreOrChange();
RunOnUiThread(() =>
{
SharedPref.UserIDNow= userID;
LoginSession.UserNow= User.GetID(userID);
});
} }
});
StartActivity(typeof(NextPage));
Finish();
}
and I retrieve the value in the next activity using SharedPref.UserIDNow to retrieve the user ID. I put the SharedPref.UserIDNow inside my static function to get current User ID
What am i missing? Everytime when I launch and login, after login the app closed like log out! and the value returns -22. Btw, -22 is a default value of my shared preference. I think it must be the ID of the User. Please help me :(
I test with your code , it works with no problem .
Some suggestions to troubleshoot .
Debug your code (add breakpoint) to check if SharedPref.UserIDNow= userID; has been executed , and also remove RunOnUiThread method ,you don't need to wrap code into it unless UI elements gets changed .
Use default SharedPreferences ,change preference as
private static ISharedPreferences preference = PreferenceManager.GetDefaultSharedPreferences(Application.Context);
Use Commit instead of Apply method on ISharedPreferencesEditor,Apply is asynchronous method which means if you read value too early ,you would get default value at that time .

Cache my static data in server for all user C#

I want to cache some static data in server. if any user request for same data cache should return that.
if i go with HttpContext.cache, it will vary by user. please help me how to do that in c#?
What I have tried:
HttpContext.Cache.Insert(cacheKey, Sonarresult, null, DateTime.Now.AddSeconds(Timeduration), Cache.NoSlidingExpiration);
i tried this but for all users will store into cache. i dont want that. first user only has to store it.
Using the application cache just like you would a session variable can do the trick for you.
e.g.
// get
string message = Application["somemessage"].ToString();
will be the same for all users.
to elaborate further, be careful where on your code you set the value for application variables because once they change, they will change for all.
// set
Application["somemessage"] = "your message";
Global.asax would be a could place to set the value of Application variables if they never change:
void Application_Start(object sender, EventArgs e)
{
// Code that runs on application startup
// here we set the value every time the application starts
Application["somemessage"] = "your message";
// the following line will get the SiteName from the web.config setting section
Application["SiteName"] = ConfigurationManager.AppSettings["SiteName"].ToString();
}
You can use application cache to do this.
void Application_Start ()
{
_cache = Context.Cache;
_cache.Insert ("mycahce", mystaticvariabledata, null,
Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration,
CacheItemPriority.Default,null);
}

Where to store user data after login with WebForms

I'm developing a WebForms web application with VS2010 in C#. I use my custom login approach to authenticate users and I don't want to use Membership framework. After user login I want to store user data as userId, username, surname, email, etc., so I can access them during the user session in all pages.
How can I do that? I don't wanna store user data in the UserData property of the FormsAuthenticationTicket.
I found this approach: Should I store user data in session or use a custom profile provider?, but I don't understand how to implement it.
I have some question:
1)in my login page to authenticate user after check credentials on db I use : FormsAuthentication.SetAuthCookie(txtUserName.Value, true); now in my default page I have:
FormsAuthenticationTicket ticket = ((FormsIdentity)(User.Identity)).Ticket; and I use ticket.Name to show username. is it correct? why do you talk about thread using Thread.CurrentPrincipal.Identity.Name ?
2) I have this code in global.asax file to read user roles and store thems into HttpContext:
void Application_AuthenticateRequest(object sender, EventArgs e)
{
if (Request.IsAuthenticated) {
SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["SQLConnStr"].ConnectionString);
conn.Open();
SqlCommand cmd = new SqlCommand("SELECT Gruppi.Name FROM Ruoli INNER JOIN Gruppi ON Ruoli.GroupID = Gruppi.GroupID INNER JOIN Utenti ON Ruoli.UserID = Utenti.UserID AND Utenti.Username=#UserName", conn);
cmd.Parameters.AddWithValue("#UserName", User.Identity.Name);
SqlDataReader reader = cmd.ExecuteReader();
ArrayList rolelist = new ArrayList();
while (reader.Read()){
rolelist.Add(reader["Name"]);
}
// roleList.Add(reader("Name"))
string[] roleListArray = (string[])rolelist.ToArray(typeof(string));
HttpContext.Current.User = new GenericPrincipal(User.Identity, roleListArray);
reader.Close();
conn.Close();
}
}
can I store user data into session as you wrote from my global.asax file rather then login.aspx page?
In the interest of easier debugging, I suggest using the Session Facade design pattern, described here, that will allow you to store the current user's data using the HttpContext.Current.Session object in a more organized fashion.
For instance, there would be a file (e.g., SessionFacade.cs) that is responsible for handling the values passed to/from the Session; in your case, it might look like:
public static class SessionFacade
{
public static int UserId
{
get {
if (HttpContext.Current.Session["UserId"] == null)
HttpContext.Current.Session["UserId"] = 0;
return (int)HttpContext.Current.Session["UserId"];
}
set {
HttpContext.Current.Session["UserId"] = value;
}
}
// ... and so on for your other variables
}
Then, somewhere else in your code, once you check that credentials are okay, you can do...
if (credentialsAreOk) {
SessionFacade.UserId = /* insert ID here */
// ...
}
...instead of manually assigning values to the Session object. This ensures your variables in Session are of the correct type, and will be easier to track while debugging. Then, to get the UserId from anywhere in your program, it's just SessionFacade.UserId.
(yes that snippet was from Eduard's answer; you should still look into that answer as it is informative as to how WebForms work; just keep in mind that calling the Session object manually in your code can be quite messy and that the Session Facade makes that process cleaner)
In case that by "web application by VS2010 in C#" you're talking about ASP.NET (MVC or Classic) and by "custom login approach" you're referring to FormsAuthentication then all you need to do is to store your later needed information at login time, onto the Session object.
Let's say you're using ASP.NET Classic and you have a login page
which has 2 inputs for Username and Password and a submit button entitled "Login"
In the button's (server side) OnClick event handler you should do something like this:
public partial class Login : System.Web.UI.Page {
protected void Page_Load(object sender, EventArgs e) {
}
private bool CheckUserPass(string username, string password) {
// access DB or some other form of storage service
return true;
}
protected void buttonLogin_Click(object sender, EventArgs e) {
bool credentialsAreOk = this.CheckUserPass(
this.textBoxUsername.Text,
this.textBoxPassword.Text
);
if (credentialsAreOk) {
this.Session["EMAIL_ADDRESS"] = "SomeEmail#SomeEmailProvider.com";
this.Session["OTHER_INFORMATION_KEY"] = "Some other stuff which you have access to during the login process";
this.Session["TIME_OF_LOGIN"] = DateTime.UtcNow;
FormsAuthentication.RedirectFromLoginPage(this.textBoxUsername.Text, createPersistentCookie: false);
}
}
}
So, in short, if you're using FormsAuthentication, then the username can be stored onto the session in the same way you're telling the FormsAuthentication system that current session should be transformed from non-authenticated to authenticated:
FormsAuthentication.RedirectFromLoginPage(this.textBoxUsername.Text, createPersistentCookie: false);
whereas other information can be placed on the Session object (just like you would add key value pairs to a Dictionary):
this.Session["TIME_OF_LOGIN"] = DateTime.UtcNow;
While it is obvious how you could later access that same information (for the respective user):
DateTime whenDidILogin = (DateTime) this.Session["TIME_OF_LOGIN"];
// this line of code can be used in any other page
// at any later time - it's like you have a global set of variables
// which exist for each and every distinct session you might have
it is maybe important to mention that the username (if not placed explicitly onto the Session object like the other examples) can be accessed by means of the Thread.CurrentPrincipal static property like so:
using System.Threading;
public void SomeWhereInYourApp() {
bool wasIAuthenticated = Thread.CurrentPrincipal.Identity.IsAuthenticated;
string whatIsMyUsername = Thread.CurrentPrincipal.Identity.Name;
// do something with that information
}
Membership provider helps you to store data and also for authentication purpose. Something like this:-
Session["UserName"] = Membership.GetUser().UserName

Saving Username into session property to help secure site

Edit Some have expressed their dislike for my particular solution presented in this problem, but please don't waste my time suggesting completely alternative methods. I have no control over the requirements of what I am working on. If you disagree with it and don't have an answer, just move along. Thanks.
For starters, this is a practice project and will not be used by the general public. I need to secure some pages in my website using session properties for username. This occurs (the username saved into session) when a correct username and password combo is entered. My boss reviewed my implementation and said that "storing the username value into the HttpSessionState directly is wrong, you should set the username property of the session, and store the session object into the HttpSessionState". Now I think I understand what parts of my code he is referring to, but changing this breaks the security (anyone can use a direct link to a page once a single user has logged in).
Make sure to read the comments in code, I added them to describe the lines in question.
What worked in terms of security, but username is stored directly into HttpSessionState:
//login.ascx.cs
private void Login_Click(object sender, EventArgs e)
{
if (sender == null || e == null)
{
throw new ArgumentNullException("Null Exception: Login_Click");
}
User user = new User();
user.Login(_username.Text, _password.Text);
if (user.IsValid() && user.GetIsUser() != false)
{
user.Save();
//the line below is what I used to make the secure pages work properly.
//but based on what my boss says, I think this is what should be changed.
Session["Username"] = _username.Text;
//What i tried instead was to set 'MySession.Current.Username = _username.Text;'
//which allowed successful login, but the pages became insecure once again.
Response.Redirect("Secure/Default.aspx");
}
else
{
DisplayErrors(user._validationErrors);
}
_errors.Text = errorMessage;
}
and MySession.cs
public string Username
{
get
{
if (HttpContext.Current.Session["Username"] == null)
{
return string.Empty;
}
else
{
return HttpContext.Current.Session["Username"].ToString();
}
}
set
{
//when the line below is uncommented, the secure pages are vulnerable
//but if I comment it out, they work properly.
//HttpContext.Current.Session["Username"] = value;
}
}
So how can I Set the username property of the session, and store the session object into the HttpSessionState while still maintaining a secure site?
EDIT: #Win, within Secure/Default.aspx.cs
private void Page_load(object sender, System.EventArgs e)
{
...
if((string)Session["Username"] != _labelusername.Text)
{
Response.Redirect(redirectLogin); //to login page
}
else {} //success
}
You should look into FormsAuthentication. There are many examples online like this one:
http://bradkingsley.com/securing-asp-net-pages-forms-authentication-c-and-net-4/

Check if user is logged in using sessions

I want to check if a user is logged in and if they are, deny them access to the registration and login pages. When a user logs in I'm setting these session variables:
HttpContext.Current.Session["LoggedIn"] = true;
HttpContext.Current.Session["FullName"] = (string)Reader["FirstName"] + " " + (string)Reader["LastName"];
Response.Redirect("Default.aspx");
And I'm checking them at the top of the register and login pages like so:
if ((bool)HttpContext.Current.Session["LoggedIn"])
{
Response.Redirect("Default.aspx");
}
However, when I try to go to the page while not logged in this exception gets thrown:
Object reference not set to an instance of an object.
I'm assuming it's ebcause the LoggedIn key doesn't exist because I only create it after a successful login.
So, how can I check if the LoggedIn key exists and if it doesn't, redirect the user to Default.aspx?
Thanks!
I think you can do a simple null check on this like....
if (HttpContext.Current.Session["LoggedIn"] != null)
{
// once inside this loop
// you can now read the value from Session["LoggedIn"]
Response.Redirect("Default.aspx");
}
you need to make shure that the object is not null before unboxing it
if(HttpContext.Current.Session["LoggedIn"]!=null)
{
if ((bool)HttpContext.Current.Session["LoggedIn"])
{
Response.Redirect("Default.aspx");
}
}
Why to avoid the default webforms authentication model altogether? Simply use web.config to define a restricted area, set all the settings correctly and you won't have to perform checks like this for every page.
But, if you want to reinvent the wheel....
You check for something that probably doesn't exist yet. You must modify your if-statement like this:
bool isLoggedIn = (HttpContext.Current.Session["LoggedIn"] == null ? false : (bool)HttpContenxt.Current.Session["LoggedIn"];
if (isLoggedIn)
{
Response.Redirect("Default.aspx");
}

Categories

Resources