I would like to store the logged in users in my asp.net application to a collection and store this collection in application state. I have a login Page and on Default.aspx page load event i have the following code:-
protected void Page_Load(object sender, EventArgs e)
{
users = (List<Users>)HttpContext.Current.Application["loggedUsers"];
if (User.Identity.IsAuthenticated == false)
{
Server.Transfer("Login.aspx");
}
if (User.Identity.Name != "")
{
users.Add(new Users { userName = User.Identity.Name.ToString() });
HttpContext.Current.Application["loggedUsers"] = users;
}
}
However when running the application, after the login an exception of Object reference not set to an instance of an object is being thrown on the code where i'm adding new objects to the list. If i comment the following line:
users = (List<Users>)HttpContext.Current.Application["loggedUsers"];
The application would run accordingly, howevever if let's say we have two users, USER A and USER B, and USER A logs in, he is added to list, however as soon as USER B logs it will overwrite USER A.
In my webservice i have the following method which will then return the list of currently logged users which works fine.
[WebMethod(EnableSession = true)]
public List<Users> getLoggedInUsername()
{
return (List<Users>)Application["loggedUsers"];
}
The problem is that when your first user is entering you have no value in the application with loggedUser key . It should be a common practice to check for NULL before casting it.
List<User> user = null;
if(HttpContext.Current.Application["loggedUsers"] == null)
{
user = new List<User>();
}
else
{
user = (List<User>)HttpContext.Current.Application["loggedUsers"];
}
Related
I am currently developing a log in and sign up page using Blazor Server. After the fields are submitted in my form, is there a way to redirect to another .razor page? I am calling a submitFields function to verify the log in information via an "#onclick" event handler for this specific example. In the submitFields function, I have tried to use Navigation Manager but it does not do anything. Further more, I tried re-initializing the page with the check being set to true so I can redirect but I am also having trouble with this approach as well. Any ideas? Below is my source code.
#code {
private string email;
private string password;
private bool check = false;
private string mySetting = "";
// form input logic
private void submitFields()
{
User person = new User();
person.connect = mySetting;
person.email = email;
person.password = password;
//when decrypting use Encrypt.hashString(password)
person.logIn();
check = person.check;
// I want to redirect to another page here
/*
if(check == true)
{
yay youre logged in, lets go to a new page!
} else
{
dont go anywhere
}
*/
}
// on load -> call this func
private void initMethod()
{
mySetting = _config.GetValue<string>("MySetting"); //on load get hidden connection string from appsettings.json
}
// on load
protected override async Task OnInitializedAsync()
{
initMethod();
}
}
First you have to inject NavigationManager. Then you can use it to navigate to another page. Example:
#inject NavigationManager NavigationManager
#code {
private void submitFields()
{
User person = new User();
person.connect = mySetting;
person.email = email;
person.password = password;
//when decrypting use Encrypt.hashString(password)
person.logIn();
check = person.check;
// I want to redirect to another page here
if(check == true)
{
NavigationManager.NavigateTo("/account/dashboard");
} else
{
dont go anywhere
}
}
}
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
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/
I have a master page that set ups some variables that I want to use across the site..
protected void Page_Load(object sender, EventArgs e)
{
//Get users name from AD
str_DomainName = HttpContext.Current.User.Identity.Name;
str_CurrentLogin = str_DomainName.Substring(5);
//Display current user information
DirectorySearcher search = new DirectorySearcher("LDAP://DCHS");
search.Filter = String.Format("(SAMAccountName={0})", str_CurrentLogin);
SearchResult result = search.FindOne();
DirectoryEntry entry = result.GetDirectoryEntry();
lbl_CurrentUser.Text = result.Properties["givenName"][0].ToString() + ' ' + result.Properties["sn"][0].ToString();
// Get SID
IntPtr logonToken = WindowsIdentity.GetCurrent().Token;
WindowsIdentity windowsId = new WindowsIdentity(logonToken);
//Set session variabls
this.CurrentFirstName = result.Properties["givenName"][0].ToString();
//this.CurrentEmail = result.Properties["mail"][0].ToString();
//this.CurrentSID = windowsId.User.ToString();
//this.CurrentUserName = str_CurrentLogin;
//this.CurrentFullName = lbl_CurrentUser.Text;
//this.CurrentDomain = str_DomainName;
this.Session.Add("currentEmail", result.Properties["mail"][0].ToString());
}
public String CurrentFirstName
{
get { return (String)ViewState["currentFirstName"]; }
set { ViewState["currentFirstName"] = value; }
}
I then call them in my defalut.aspx page as follows:
protected void Page_PreRender(object sender, EventArgs e)
{
//try
//{
lbl_FullName.Text = Master.CurrentFullName;
lbl_SID.Text = Master.CurrentSID;
testLabel.Text = Master.CurrentEmail;
//}
//catch (Exception ex)
//{ }
}
This works fine.. If I however navigate away from the default page, then I get the following error..
Object reference not set to an instance of an object.
One the lbl_FullName.Text = Master.CurrentFullName; line
If I uncomment the try catch then it works fine, but I don't believe that this is the correct method of avoiding the fault..
I'm only new to ASP, so be nice..
EDIT:
The variabes are being set in Master.cs as follows.
public String CurrentUserName
{
get { return (String)ViewState["currentUserName"]; }
set { ViewState["currentUserName"] = value; }
}
A few questions:
Which side of the expression is generating the error: this.lbl_FullName or this.Master?
If it's the former, then there's something funky going on in your page.aspx.designer.cs file. Make sure the label control has been declared in there (this file is automatically generated by visual studio, but can sometimes not update properly). You should see a single line like this:
protected
global::System.Web.UI.WebControls.Label
lbl_FullName;
If it's the this.Master property then your page is obviously not referencing your masterpage. Check the page directive (the top line of your .aspx file) and make sure that the DynamicMasterPage value is set and that the path is correct.
On a design note, the masterpage isn't the best place to "store variables". The masterpage should literally just be used to initialise the common parts of the page across your site.
If you need to gather information from a user and use it across several pages, use session variables. This is a method of storing objects "in memory" for as long as the user's browser is open.
Items can be added to the session as follows:
this.Session.Add("fullName", fullName);
Items can then be retrieved later from any other page / usercontrol in your site as follows:
string fullName = (string)this.Session["fullName"];
ViewState is per-page. When you navigate to the new page, it isn't set.
Your master page should put these into Session instead.
I have designed several Client/Server applications. I am working on a project that involves a user logging in to gain access to the application. I am looking at the most efficient and "simple" method of storing the users permissions once logged in to the application which can be used throughout restricting access to certain tabs on the main form.
I have created a static class called "User" detailed below:
static class User
{
public static int _userID;
public static string _moduleName;
public static string _userName;
public static object[] UserData(object[] _dataRow)
{
_userID = (int)_dataRow[0];
_userName = (string)_dataRow[1];
_moduleName = (string)_dataRow[2];
return _moduleName;
}
}
When the user logs in and they have been authenticated, I wish to store the _moduleName objects in memory so I can control which tabs on the main form tab control they can access, for example; if the user has been assigned the following roles in the database: "Sales Ledger", "Purchase Ledger" they can only see the relevant tabs on the form, by way of using a Switch - Case block once the login form is hidden and the main form is instantiated. I can store the userID and userName variables in the main form once it loads by means of say for example:
Here we process the login data from the user:
DataAccess _dal = new DataAccess();
switch (_dal.ValidateLogin(txtUserName.Text, txtPassword.Text))
{
case DataAccess.ValidationCode.ConnectionFailed:
MessageBox.Show("Database Server Connection Failed!");
break;
case DataAccess.ValidationCode .LoginFailed:
MessageBox.Show("Login Failed!");
_dal.RecordLogin(out errMsg, txtUserName.Text, workstationID, false);
break;
case DataAccess.ValidationCode .LoginSucceeded:
frmMain frmMain = new frmMain();
_dal.GetUserPrivList(out errMsg,2); //< here I access my DB and get the user permissions based on the current login.
frmMain.Show();
this.Hide();
break;
default:
break;
}
private void frmMain_Load(object sender, EventArgs e)
{
int UserID = User._userID;
}
That works fine, however the _modules object contains mutiple permissions/roles depending on what has been set in the database, how can I store the multiple values and access them via a Switch-Case block?
If I am understanding properly, you want to be able to store permissions/roles as a value in a database per user.
I believe you can write an integer to a database field like : RolesID. Write to you database field the value of the flag. Something like:
[Flag]
public enum ROLES
{
Administrator = 1,
User = 2,
OtherRole3 = 4,
OtherRole4 = 8
}
You should be able to read that value in and assign to a field declared as:
ROLES userRoles = GetRoleValueFromDB();
I'm pretty certain I've done this before.
HTH...