I'm having a rough time with this membership stuff.
OK, so, it's really odd. I can register a user. I can register, I can login. However, when I go to register ANOTHER user the user isn't saved in the database and I get a
Membership credential verification failed event when the user tries to login (I assume because the user is never being saved).
Here is the code I am using to save a new user.
On the page:
protected void btnRegister_Click(object sender, EventArgs e)
{
if (false == ValidatePage()) return;
FormsAuthentication.SignOut();
MembershipCreateStatus status;
Data.User user = UserManager.CreateUser(txtEmail.Text.Trim(), txtPassword.Text.Trim(), out status);
switch (status)
{
case MembershipCreateStatus.Success:
UserManager.Save(user);
break;
default:
lblMessage.Text = status.ToString();
break;
}
Response.Redirect("~/login.aspx");
}
the CreateUser method:
public static User CreateUser(string username, string password, out MembershipCreateStatus status)
{
using (TransactionScope transaction = new TransactionScope())
{
MembershipUser aspnetUser = Membership.CreateUser(username, password, username, null, null, true, out status);
User hqUser = null;
if (status == MembershipCreateStatus.Success)
{
hqUser = new User();
//these properties are only for issues
//that won't blow up. They can be safely removed from the system.
//the aspnet membership tables take care of this stuff for us.
hqUser.LastLoginDate = DateTime.Now;
hqUser.DateCreated = DateTime.Now;
//end properites.
hqUser.Email = username;
hqUser.MembershipID = (Guid)aspnetUser.ProviderUserKey;
Save(hqUser);
}
transaction.Complete();
return hqUser;
}}
The extra save method is for saving the user in the app's database. The user is not getting into the membership database though so I know it's dying before that.
anyone see anything obvious that's burning me? Thanks!
Have you checked to see this is not a problem with password complexity? I know I have had issues with this in the past...
You redirect the page before you are able to see the output if the status is not equal to success.
Btw. it might be better to inherit the sqlmembership provider and extend it with your own extra db inserts, at least if you are not inserting extra data. Or are you asking more than the default stuff on the first creation of the account?
Try it like this code and see what the value of the enum is in the lblMessage
protected void btnRegister_Click(object sender, EventArgs e) {
if (!ValidatePage()) return;
FormsAuthentication.SignOut();
MembershipCreateStatus status;
Data.User user = UserManager.CreateUser(txtEmail.Text.Trim(), txtPassword.Text.Trim(), out status);
switch (status) {
case MembershipCreateStatus.Success:
UserManager.Save(user);
Response.Redirect("~/login.aspx");
break;
default:
lblMessage.Text = status.ToString();
break;
}
}
grrgr, stupid markup thing
Hope this helps.
My first guess is that ValidatePage() return false.
Related
My session is not getting destroyed. This is how I set it up in Login.aspx.cs:
Session["User"] = UserName.Text; // Set the session called User.
Link on the MasterPage:
<img src="images/login.png"><span runat="server" id="authspan">Login</span>
The text in the link changes depending on whether the user has session or not:
if (Session["User"] != null)
{
authspan.InnerHtml = "Logout";
}
else
{
authspan.InnerHtml = "Login";
}
This link redirects to Login.aspx file in which on PageLoad I tell the code to close the session. In theory, this should work, right?
protected void Page_Load(object sender, EventArgs e)
{
if (Session["User"] != null)
{
Response.Redirect("Default.aspx"); // Redirect user.
Session["User"] = null;
Session.Remove("User");
}
else
{
// run code that logs the user in, and sets up the session.
}
}
How can I end it for the logged in user correctly?
You must first clear session and then redirect.
Session["User"] = null;
Session.Remove("User");
Response.Redirect("Default.aspx"); // Redirect user.
Also note that, it is safer to remove session id on client side too:
var sessionCookie = new HttpCookie("ASP.NET_SessionId");
sessionCookie.Expires = DateTime.Now.AddDays(-1);
Response.Cookies.Add(sessionCookie);
You should use:
Session.Clear();
Response.Redirect("Default.aspx");
To remove the value from session in different ways
//Set the session variable
Session["User"]=Value;
//Destroy the session variable
Session.Remove("User");
Session["User"]=null;
// Abandon will destroy the session completely, meaning that you need to begin a new session before you can store any more values in the session for that user
Session.Abandon();
//Clearing the session will not unset the session, it still exists with the same ID for the user but with the values simply cleared.
Session.Clear();
Call Session.Abandon(); (and I must write at least 30 chars)
I am working on a password change method, this view is enforced by one of many conditions. The first condition is if the LastLoggedin field in the database is null. I have this field set to null in my test database to force the password change events.
I have coded a method to change the password after performing some tests, but I cannot get past the first test because the controller method that the click event calls returns the user back to the log on method, which in turns checks the LastLoggedin field in the database which is still null because I have not yet logged in. I tried to change that value from within my change password method using the following code:
public bool SavePassword(UserModel user, PasswordRecoveryModel password)
{
try
{
string newPass = password.PasswordNew;
string newHash = PasswordManager.EncryptPassword(newPass);
User domainObject = UnitOfWork.UserRepository.GetItem(user.EntityId);
bool hasUsedPassword = UnitOfWork.UserRepository.HasHadPassword(domainObject, newHash, DateTime.Now.AddMonths(-6));
if (hasUsedPassword.Equals(true))
{
return true;
}
User lastLogged = UnitOfWork.UserRepository.GetItem(user.EntityId);
lastLogged.LastLoggedIn = DateTime.Now;
lastLogged.VerifiedOn = DateTime.Now;
UnitOfWork.UserRepository.Update(lastLogged);
lastLogged.VerifiedOn.Equals(DateTime.Now);
lastLogged.LastLoggedIn.Equals(DateTime.Now);
user.Password = newHash;
user = SaveModel(UnitOfWork.UserRepository,
user,
Mapper.User.ModelToDomain,
Mapper.User.DomainToUserModel);
CommitTransaction();
return false;
}
catch (Exception ex)
{
OnServiceException(ex);
throw;
}
}
But I am still not getting anything other than the new password saved in the database, I am verifying this by running a query on my username. How do I update this field so I can get by this test on password change, and is it even acceptable to do this? In our old product it was done in a very complex manner creating a temporary user object ant using that to get past the test and on to the next test. I am trying to simplify the process.
I am new to MVC and programming in general any help would be appreciated.
EDIT found my problem, as usual over thinking the issue, here is the updated code:
if (hasUsedPassword.Equals(true))
{
return false;
}
user.LastLoggedIn = DateTime.Now.ToString();
user.Password = newHash;
user = SaveModel(UnitOfWork.UserRepository,
user,
Mapper.User.ModelToDomain,
Mapper.User.DomainToUserModel);
CommitTransaction();
return true;
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
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"];
}
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/