i am new to windows programming, as we use Store user's details in Session when user successfully logged into a web application and check the session in master page every time, if it will null then redirect the user to login page. I want to do the same thing in Windows application, i have created a login form: the code is written below:
private void btnLogin_Click(object sender, EventArgs e)
{
clsLogin obj = new clsLogin();
DataTable dtLogin = obj.Login_Check(txtUserName.Text.Trim(), txtPassword.Text.Trim());
if (dtLogin.Rows.Count > 0)
{
if (dtLogin.Rows[0]["result"].ToString() == "3")
{
lblMessage.Text = "Password does not matched";
}
else
if (dtLogin.Rows[0]["result"].ToString() == "2")
{
lblMessage.Text = "User does not exists";
}
else
{
Staff.Home home = new Staff.Home();
this.Hide();
home.Show();
}
}
}
}
Now what i want to do is: store the user info some where and when user click on Log off then it will destroy that session and it will open the Login form.
i know it is a very silly question, as i am new to windows programming its tough for me, please help.
Apart from the obvious issues with the code:
Direct access to rows by index
Login being done in the event handler directly
You should have separate login service and data access service
I would:
Create a login service that maintains the current logged in user details and performs the authentication itself.
Create a data access service that the login service can call to access the datastore
Then in your event handler you just need to call:
if (loginService.Authenticate(username, password))
{
// Do your UI handling here
}
then the loginService will have a .CurrentUser property for example and you can go from there.
e.g.
public class LoginService
{
private User _currentUser;
public bool Authenticate(string username, string password)
{
if (_currentUser != null)
{
Logout();
}
else
{
var user = DataAccess.Get("users").SingleOrDefault(u => u.Username = username);
if (user == null)
{
throw new Exception("No user with that username found");
}
if (password == user.Password)
{
_currentUser = user;
return true;
}
else
{
return false;
}
}
}
public User CurrentUser
{
get { return _user; }
}
}
In a Web application it is supposed that there are multiple clients connected to the single server; you should use Session to distinguish between them and to pass data to each of them "there and back again". For a desktop application this problem does not exist at all - there is exactly one user and his data is all here: you do not need some special mechanism like Session for it.
This means that you may use a number of different approaches to pass data from your form. In your example it seems more logical to pass data to your "home" form directly, either through constructor
else
{
var userData = .... (txtUserName.Text);
Staff.Home home = new Staff.Home(userData);
this.Hide();
home.Show();
}
or through a property
else
{
var userData = .... (txtUserName.Text);
Staff.Home home = new Staff.Home();
home.UserData = userData;
this.Hide();
home.Show();
}
This is only an example, there are a lot alternatives - just think about this "single user, always on site" model.
Related
I need an advice please.
I have an C# app (and WPF for design) with an ActiveDirectory authentification required. I currently just check if the Username and Password are corrects before log the user in. But, now, I have to grant access to some features depending on who log onto my app (some users may have full access, some others will have locked features).
I wonder how to do this ...
If someone have an example, or any guideline :)
Thank's a lot.
It realy depends on what your Architecture should look like. I would suggest different modules each including a initialization class which may add buttons to a menu in a init method. Then you could use annotation on this class including the required user-rights. When ever you initialize your whole application you could iterate over the initialization classes and call the init method if the user has access.
You could create classes that implements the IIdentity and IPrincipal interfaces and override the application thread's default identity in your App.xaml.cs file:
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
//Create a custom principal with an anonymous identity at startup
CustomPrincipal customPrincipal = new CustomPrincipal();
AppDomain.CurrentDomain.SetThreadPrincipal(customPrincipal);
base.OnStartup(e);
}
}
You could then use the PrincipalPermissionAttribute to perform either declarative or imperative security checks throughout your application.
Please refer to this blog post for more information and a complete example.
I finally found a solution.
1st : I check if user is authenticated. If true, "goto" 2nd ;)
public bool IsAuthenticated(string username, string passwd, string domain)
{
try
{
DirectoryEntry entry = new DirectoryEntry("LDAP://" + domain, username, passwd, AuthenticationTypes.Secure);
DirectorySearcher search = new DirectorySearcher(entry)
{
Filter = "(objectClass=user)",
SearchScope = SearchScope.Subtree
};
SearchResult result = search.FindOne();
return (result != null);
}
catch (Exception ex)
{
throw new Exception("Authentication Error.\n" + ex.Message);
}
2nd : I check which group the user is in. My access differs mainly on 3 groups. I used a simple conditionnal statement like this :
if (IsAuthenticated(user, password, LdapCmb))
{
// Connection ok
if (AuthenticateGroup(user, password, userLdap, GroupADM))
{
accessRights = "ADM";
// Variable passed to another class (for locking down some contents)
}
else if (AuthenticateGroup(user, password, userLdap, OtherGroup1))
{
accessRights = "OTHER1";
// Variable passed to another class (for locking down some contents)
}
else if (AuthenticateGroup(user, password, userLdap, OtherGroup2))
{
accessRights = "OTHER2";
// Variable passed to another class (for locking down some contents)
}
else
{
MessageBox.Show(this, "You are not authorized to use this application.", MessageBoxButton.OK, MessageBoxImage.Warning);
logIt.AppendText("User " + user + " isn't granted for use");
Application.Current.Shutdown();
}
Close();
}
else
{
MessageBox.Show(this, "You are not authorized to use this application.", MessageBoxButton.OK, MessageBoxImage.Warning);
logIt.AppendText("User " + user + " isn't granted for use");
Close();
}
And finally, here is the "authenticateGroup" method :
public bool AuthenticateGroup(string userName, string password, string domain, string group)
{
try
{
DirectoryEntry entry = new DirectoryEntry("LDAP://" + domain, userName, password);
DirectorySearcher mySearcher = new DirectorySearcher(entry)
{
Filter = "(&(objectClass=user)(|(cn=" + userName + ")(sAMAccountName=" + userName + ")))"
};
SearchResult result = mySearcher.FindOne();
foreach (string GroupPath in result.Properties["memberOf"])
{
if (GroupPath.Contains(group))
{
return true;
}
}
}
catch (DirectoryServicesCOMException ex)
{
Console.WriteLine(ex.Message);
}
return false;
}
It's certainly not the best method... but at least, it works as expected at this moment. Now I have to test it deeper.
Thank's anyway.
I am working on Xamarin forms applicaiton which will have three welcome pages while the user is logging into the applicaiton for the first time, if the user user is trying to start the application after logging in only dashboard has to be displayed. I have written the following code for that :
public LoginUserInfoDbModel SaveUserDetails(LoginUserInfoDbModel model)
{
if(model.LoggedInUser!=null)
{
return null;
}
else
{
connection.Insert(model);
return model;
}
}
and called the above method in LoginPage.xaml.cs in the following way :
if (model.ResultString == "Valid")
{
App.UserDatabase.SaveUserDetails(model);
await DisplayAlert("", "You have logged in succesfully ", "Ok");
await Navigation.PushAsync(new DashBoardPage());
}
So now I need to check whether the User is already a existing user or not in DB, so I have written the following code in App.xaml.cs :
var connection = DependencyService.Get<ISQLiteDb>().GetConnection();
var c=connection.CreateTableAsync<LoginUserInfoDbModel>().Result;
var UserData = connection.Table<LoginUserInfoDbModel().ToListAsync().Result?.FirstOrDefault();
if(UserData != null)
{
MainPage= new DashBoardPage();
}
else
{
MainPage=new WelcomePages();
}
But this code is not working I am getting null reference Exception and some other exceptions, So do we have any alternative for this scenario or else can you suggest any modifications for this code ?
I have a sectiontree which varies based on the current logged in users UserType.
The thing is that if i log-out from the backoffice, and logs in with a new user with a lower UserType, the tree is not refreshed - The code is not rerun to generate the tree.
This means that the user with a non administrative UserType can access administrative areas in the section, as long as an administrator have been logged in earlier on the same solution.
How would i make the SectionTree refresh on new users login?
Update
protected override TreeNodeCollection GetTreeNodes(string id, FormDataCollection queryStrings)
{
var sectionApi = new SectionApiController();
// Root handler
if (id == Constants.System.Root.ToInvariantString())
{
this.RootHandler();
}
else if(id.Contains("COUNTRY_") || id.Contains("LEVEL_") )
{
var section = new IdConvert(id);
if ( section.Area.Equals("country") )
{
this.FirstLevelHandler(section.Id);
}
else if (section.Area.Equals("level"))
{
this.GetLevels(section.Id);
}
// Render clubs.
this.ClubHandler();
// Render levels
this.LevelHandler();
} else if(id.Contains("CLUB_")) {
}
else if(id.Contains("SPORTS_")) {
var Country = new IdConvert(id);
this.SportsHandler(Country.Id);
}
else if (id.Contains("QUESTIONS_"))
{
var Country = new IdConvert(id);
this.QuestionsHandler(Country.Id);
}
return this._nodes;
}
The Tree works fine, it renders what it should render. But It doesent refresh upon new user login.
I'm using the following to check wether or not a person is "admin"
public static bool IsAdministrator()
{
try
{
if (_curNewUser == null)
{
GetCurrentUser();
}
if (_curNewUser.UserType.Alias == "admin")
{
return true;
}
}
catch (Exception e) { }
return false;
}
Based on a comment you are not clearing _curNewUser when user logs out and that's why you are seeing this issue.
Instead of keeping the reference to _curNewUser you should use umbraco built in UmbracoContext.Current.Security.CurrentUser directly in your UserProvider and that will fix it, something like this:
public static bool IsAdministrator()
{
var user = UmbracoContext.Current.Security.CurrentUser;
return user != null && user.UserType.Alias == "admin";
}
No need for you to hook up to logout events or anything like that.
im stuck with this and im really going to bang my head against a wall in a minutes
I have a logging page where the user enters there username and password and clicks login when they have pressed this a function is called to get all the user details i.e firstname surname Email AccountType Examtaken etc within the function im trying to set "Get; Set;" Properties so i can use them on the home page, but for some stupid reason un-known to me its not working! below you will see the method that is called when the user clicks login
public class ExamMethods
{
public int UserID { get; set; }
public string FirstName { get; set; }
public string Surname { get; set; }
public string Email { get; set; }
public int AccountType { get; set; }
public bool ExamTaken { get; set; }
private enum Datafield
{
UserID,
FirstName,
Surname,
Email,
AccountType,
ExamTaken,
}
public Hashtable CheckLogin(Hashtable Usercredentials)
{
try
{
SqlConnection Connection = new SQLAccess().CreateConnection();
SqlCommand Command = new SqlCommand("GetUserDetails", Connection);
Command.CommandType = System.Data.CommandType.StoredProcedure;
foreach (DictionaryEntry SpParameter in Usercredentials)
{
Command.Parameters.Add(new SqlParameter(SpParameter.Key.ToString(), SpParameter.Value.ToString()));
}
SqlDataReader da = Command.ExecuteReader();
while (da.Read())
{
Details.Add("UserID", da["UserID"]);
UserID = (da.IsDBNull((int)Datafield.UserID)) ? 0 : da.GetInt32((int)Datafield.UserID);
Details.Add("FirstName", da["FirstName"]);
FirstName = (da.IsDBNull((int)Datafield.FirstName)) ? "" : da.GetString((int)Datafield.FirstName);
Details.Add("Surname", da["Surname"]);
Surname = (da.IsDBNull((int)Datafield.Surname)) ? "" : da.GetString((int)Datafield.Surname);
//Details.Add("AccountType", da["AccountType"]);
//AccountType = (da.IsDBNull((int)Datafield.AccountType)) ? 0 : da.GetInt32((int)Datafield.AccountType);
//Details.Add("ExamTaken", da["ExamTaken"]);
//ExamTaken = (da.IsDBNull((int)Datafield.ExamTaken)) ? false : da.GetBoolean((int)Datafield.ExamTaken);
}
Connection.Close();
da.Close();
return Details;
}
catch
{
Console.WriteLine("Error Checking Login Details");
return Details;
}
}
}
as you can see from the above in the while(da.read) im assigning the values to a hashtable and the get set methods when debuggin i can see values going in! and im 100% this values arent null or empty
the code then reverts back to the login page with it results if all is fine then response.redirect to the home page where the user can take the exam, but in the page load of the home.aspx i have a label which i want to popualte with the users name so i reference the get propertie on the ExamMethods class but its null? how can this be possible? what am i missing?
This is the code for the behind home.aspx page
public partial class Home : System.Web.UI.Page
{
Hashtable UpdateUser = new Hashtable();
protected void Page_Load(object sender, EventArgs e)
{
Methods.ExamMethods obj_UserDetails = new Methods.ExamMethods();
if (Request.QueryString["uid"] == null)
{
Response.Redirect("Login.aspx");
}
else
lblUserName.Text = obj_UserDetails.FirstName;
}
Is it because I have used reponse.redirect from the login page to the home page that the get set methods are nothing?
Variables aren't shared among web pages when you are working with web pages. As you might know HTTP is a stateless protocol.
So how do I do this?
You need state management. You need a way to pass the information around. From what I see, Sessions seems to be best place to store this data that you require to use in multiple pages.
But sessions are not the only state management option you have. You have many more depending on what you want to store, how much you want to store and where/when you want to access them.
I suggest you read up on ASP .NET State Management also read up on recommendations to understand which state management feature to use in which scenario.
In Page_Load method you're creating a new instance of Methods.ExamMethods() each time so all of its properites are not initialized. After you are redirected to login page, perform login and are redirected back, Page_Load is executed again and a new instance of the class is created.
The preffered way of doing it would be just reading user's data from database based on uid when you have it defined in theQueryString.
protected void Page_Load(object sender, EventArgs e)
{
Methods.ExamMethods obj_UserDetails = new Methods.ExamMethods();
if (Request.QueryString["uid"] == null)
{
Response.Redirect("Login.aspx");
}
else
{
if (!Page.IsPostback)
{
//read value of uid parameter
int uid = Request.QueryString["uid"];
//access database to retrieve user's details
obj_UserDetails = GetUserDetails(uid);
lblUserName.Text = obj_UserDetails.FirstName;
}
}
}
It's also worth monetioning that you can use Page.IsPostback attribute to fill controls with user's data. On postbacks ViewState mechanism should preserve controls' contents.
There are also some other mechanisms that allow you to pass data between pages, like Session state. This can be used if you need user details on more pages than just those two. This way you don't have to access the database to often.
Using Server.Transer() method to redirect user to another page and using PreviousPage object can give you access to other page as well, but I suppose using QueryString and reading data directly on Home page would be the most appropriate in your case.
Links that can be helpful:
ASP.NET Session State Overview
Understanding ASP.NET View State
HttpServerUtility.Transfer method
Instances don't stay alive when you browse through pages on the web, you can store things you need in a session and get it when the new page loads
you can do this when you need to store the data
Session["data"] = new Data("SomeData");
and you can do this when you need the data again
var data = Session["data"] as Data;
if(data != null)
//do something with the data
I wrote the following code to log in to my application using C# and LINQ. It connected to a SQL service oriented database that I have created in Visual Studio. The problem that I am having is one that I do not understand and am hoping that someone can help me about here. I have created two message boxed to try to see the output of my code buy I am not getting anything from it.
If anyone could help that would be great!
public bool UserLogin(string User, string Pass)
{
var Database = new ExampleDataSet();
var query = from Employee in Database.Employee
where (Employee.EmployeeID.ToString() == Employee.ToLower() && Employee.Password == Pass)
select Employee;
if (query.Count() != 0)
{
return true;
MessageBox.Show("You are logged in");
}
return false;
MessageBox.Show("You are not logged in");
}
private void cmdLogin_Click(object sender, EventArgs e)
{
string User = (txtUser.Text);
string Pass = (txtPass.Text);
UserLogin(User, Pass);
}
From the code you wrote, it seems that the problem is that you compare the string representation of an Employee with its EmployeeId property Employee.EmployeeID.ToString() == Employee.ToLower(). This line will always return false unless you override ToString() method of Employee class to return the property EmployeeId (which I presume you didn't).
Try this instead (assuming that parameter User contains the name of the user):
using(var dataSet = new ExampleDataSet())
{
var loggedIn = dataSet.Employee.Any(e=>e.UserName == User && e.Password == Pass);
var message = loggedIn ? "You are logged in" : "You are not logged in";
MessageBox.Show(message);
return loggedIn;
}
When you return, the function execution will stop, because it's done and will return the value to what it was called from. So anything after your return won't happen. Try putting MessageBox.Show before return:
MessageBox.Show("You are logged in");
return true;
And the same for the false version.
The Message boxes wont show as they are after the return statements - move your message boxes to before the returns to see them.
I have made changes in your code....Your if-else part is not valid......You are comparign employee.ID with employee itself..Try out with following code.....
public bool UserLogin(string User, string Pass)
{
var Database = new ExampleDataSet();
var query = from Employee in Database.Employee
where (Employee.EmployeeID.ToString().ToLower().Equals(User.ToLower())&& Employee.Password.ToString().ToLower().Equals(Pass.ToLower())
select Employee;
if (query.Count() != 0)
{
MessageBox.Show("You are logged in");
return true;
}
else
{
MessageBox.Show("You are not logged in");
return false;
}
}
private void cmdLogin_Click(object sender, EventArgs e)
{
string User = (txtUser.Text);
string Pass = (txtPass.Text);
UserLogin(User, Pass);
}
If you mean user = employeeId
Employee.EmployeeID.ToString() == user.ToLower()
if not :
Employee.EmployeeName.ToLower() == user.ToLower()
About the message box, you should know any statement after return will not be executed
Writing your own user authentication is not recommended. It is very difficult to do it right, and in most cases you can use one that is already provided by Windows or the dot net framework.
For example, your application should not store the users passwords in plain text. If your application or database is compromised, the attacker will not only gain full access to your application, but a list of passwords which it is likely the users have also used elsewhere.
If you need to store the users credentials, they should first be salted, and then hashed with a secure hashing algorithm. This prevents anyone who gains access to the database from learning users passwords.
To verify the password, you look up the salt in the database, append the password to it, hash the result, and then compare that with the stored value. If they are the same, then the user entered the correct password.
If you are writing an application that will be used in a windows domain, you can use Active Directory groups to control access to your application. On the simplest level, you can store your application in a folder which is only accessible by the authorised users.
You can also use groups to control access to the database the application connects to. If you are using SQL server, each group should be placed in a SQL database role, which is in turn granted the necessary permissions for that role.
From within the application, you can look up the users group membership, and use it to determine which forms / menu options to show, or exit the application if they are not authorised.
If you are writing an ASP.Net application, consider using MemberShip and Roles which are built in to the framework.