How to pass the asp.Identity object to a second register page - asp.net

I am building a much more advanced registration process which consists of 3 pages, the first page is a form that grabs a username(email form) and a password with confirmation. The button click on this page creates the user in an unverified state in the db and redirects to the page where the profile is created. Once the create profile button is clicked and the profile is created in the db the redirect takes you to the Credit Card info page where the form is filled out, the credit card is verified and then that info is written to a table in the database.
I have disabled the loggedin user display in the header so that I can use the registrants First and Last name which arent entered until the Credit Card page. Since the identityUser is required for the sign on and thus to populate the loggedin user control, how can I pass this object from page to page?
Code where original template was logging in the user: (Note:I commented out the sign in code)
Protected Sub CreateUser_Click(sender As Object, e As EventArgs)
Dim userName As String = UserNameCtrl.Text
Dim manager = New UserManager()
Dim newuser = New IdentityUser() With {.UserName = userName}
manager.UserValidator = New UserValidator(Of IdentityUser)(manager) With {.AllowOnlyAlphanumericUserNames = False}
Dim result = manager.Create(newuser, Password.Text)
If result.Succeeded Then
Session("email") = newuser.UserName
Session("userid") = newuser.Id.ToString()
'uncomment the code below if you want the auto sign in to occur
'IdentityHelper.SignIn(manager, newuser, isPersistent:=False)
IdentityHelper.RedirectToReturnUrl(Page.ResolveUrl("~/Account/CreateProfile.aspx?Guid=" & newuser.Id.ToString()), Response)
Else
ErrorMessage.Text = Encoder.HtmlEncode(result.Errors.FirstOrDefault())
End If
End Sub
I now call this routine to sign in the user once the third page of the registration process is completed. (Session("userid") is the new registrants generated userid)
Private Sub SignInUserOnFormCompletion()
Dim manager = New UserManager()
manager.UserValidator = New UserValidator(Of IdentityUser)(manager) With {.AllowOnlyAlphanumericUserNames = False}
Dim newuser = New IdentityUser() With {.Id = Session("userid").ToString()}
IdentityHelper.SignIn(manager, newuser, isPersistent:=False)
End Sub
The problem is the above doesnt work as the newuser somehow has different credentials. How can I pass the original newuser from the first page to the third page where I can use it in the SignInUserOnFormCompletion subroutine? Do I create a cookie and pass it around that way?
This is a new topic for me so I'm not familiar with the proper methods to accomplish this.

If you use multiple pages arranged as a wizard, then you will need to pass data between the pages.
However, if you use a single page with a MultiView or Wizard control, then you won't need to do that. Just arrange your current pages as separate views within the MultiView, and use Session state to retain data across the post backs.

Related

How do I log a user back in after change of Email/Username? - Asp.net/VB.Net

I found this code on a site which was written for me and works, and I'm trying to use it on a new site. The code checks that a emailAddress doesn't already exist when a user edits their account details, and because the emailAddress is also used as the underlying .NET membership username it needs to change that too. So far I've managed to get it to change the email address in tblAccounts which is done with this call:
acc.UpdateUsername(txtEmailAddress.Text, lblEmailAddress.Text)
Then it needs to check if the user changing the email is the logged in user and re-log them back in. This doesn't seem to work as I get this error from the siteMaster when it tries to redirect to the homepage:
System.NullReferenceException: Object reference not set to an instance of an object.
The error is caused in the siteMaster when it tries to check messages for logged in user and it flags up the last line of this as where the error occurs:
If HttpContext.Current.User.Identity.IsAuthenticated Then
hypSettings.visible=true
Dim counter As Integer = messaging.CheckUnreadMessages(Membership.GetUser.ProviderUserKey)
It therefore looks like the email address is being updated where it should, but the site isn't logging the user back in correctly. As I say, it works on the site where I took the code from and there isn't much difference between the sites, but I don't understand memberships and cookies too well so I'm not sure if something needs altering elsewhere?
Here's the code for changing the users email address:
'Check if the Role has been changed
Membership.ApplicationName = "/OCBS"
Dim userID As Guid = Guid.Parse(Request.QueryString("aID"))
Dim usr As MembershipUser = Membership.GetUser(userID, False)
'Now check if the email address has been changed, because the email address is used for the username then the underlying .NET membership username needs changing
If txtEmailAddress.Text <> lblEmailAddress.Text Then
'Email has been changed, update the username for this user
Dim acc As New accounts(Guid.Empty)
acc.UpdateUsername(txtEmailAddress.Text, lblEmailAddress.Text)
'Check if the user changing the email is the logged in user and re-log them back in
If User.Identity.Name = lblEmailAddress.Text Then
'FormsAuthentication.SetAuthCookie(txtEmailAddress.Text, False)
Response.Cookies.Clear()
Dim expiryDate As DateTime = DateTime.Now.AddDays(100)
Dim ticket As New FormsAuthenticationTicket(2, txtEmailAddress.Text, DateTime.Now, expiryDate, True, [String].Empty)
Dim encryptedTicket As String = FormsAuthentication.Encrypt(ticket)
Dim authenticationCookie As New HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket)
authenticationCookie.Expires = ticket.Expiration
Response.Cookies.Add(authenticationCookie)
End If
End If
Oooh, I've managed it.. I added this..
Session.Abandon()
FormsAuthentication.SignOut()
after line: Response.Cookies.Clear()

show user's details from table on aspx when logged in

I posted a similar question previously but quickly deleted it as the question had a number of errors and was not clear for readers.
I am creating a log in for a patient and when logged in (from the log in page login.aspx) I want them to be redirected to a page (in this case user.aspx) when the log in is authenticated and show their details from a table.
So far I can just get a label to provide user logged in correct or user log in incorrect.
I have a patient table as follows - this is all dummy data and made up user/accounts:
This is the code behind file, have I set a session correctly? and how when the user is authenticated can they be redirected to user.aspx with their corresponding details from a table (for instance their user details)
Imports System.Data.SqlClient
Imports System.Data
Partial Class Pages_Login
Inherits System.Web.UI.Page
Protected Sub btnlogin_Click(sender As Object, e As EventArgs) Handles btnlogin.Click
Dim patientNo As String
Dim password As String
Dim bAuthethicated As Boolean
patientNo = txtuser.Text
password = txtpassword.Text
bAuthethicated = CheckUser(patientNo, password)
If bAuthethicated Then
lblresult.Text() = "correct"
Else
lblresult.Text() = "Incorrect Student Number and/or Password"
End If
End Sub
Public Function CheckUser(patientNo As String, password As String) As Integer
Dim cmdstring As String = "SELECT * FROM Patient Where Username=#PATIENTNO AND Password=#PASSWORD"
Dim found = 0
Using conn As New SqlConnection("Data Source=(LocalDB)\v11.0;AttachDbFilename=C:\Users\Laura\Final_proj\App_Data\surgerydb.mdf;Integrated Security=True;Connect Timeout=30")
Dim cmd = New SqlCommand(cmdstring, conn)
cmd.Parameters.Add("#PATIENTNO", SqlDbType.NChar).Value = patientNo
cmd.Parameters.Add("#PASSWORD", SqlDbType.NChar).Value = password
conn.Open()
Dim reader = cmd.ExecuteReader()
While reader.Read()
Session("PatientId") = CInt(reader.Item("PatientId"))
found = CInt(reader.Item("PatientId"))
End While
reader.Close()
End Using
Return (found)
End Function
End Class
I hope someone can help. If I can provide any more information or direction on the question please let me know.
Rather than showing the user that they have successfully logged in, just add the following line of code to redirect them to the user.aspx page:
Response.Redirect("user.aspx", True)
On the user page, you need to check if the Session("PatientId") is empty, if so, then redirect back the login page. If it does have a value, ensure it is a number and then use it to load up the patient details with another DB call.
Also another tip, I noticed your passwords are in plain text. I would highly recommend that you one-way hash them using a simple function for additional security. You can then use the same function to hash the password used on the login page to compare against the database value.

Evaluating whether a page is the result of a referral from a particular page

I have an Edit Profile page which allows users to change their information - currently it only allows users who have a record in the table 'userprofiles' to edit their information. I want newly registered users to be able to edit their profiles as well.
At the minute, I am using the ASP.NET membership system with the appropriate asp.net_ tables in an Access database to store user credentials. The 'userprofiles' table is a separate table which has more personal information in it. There is no link between the two tables
Here is my code behind:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If IsCrossPagePostBack Then
SeparateNewUserFunction()
Return
End If
If Not IsPostBack Then
DisplayData()
SaveConfirmation.Visible = False
End If
End Sub
And here is my DisplayData() function just if anyone was interested as to what it does:
Protected Sub DisplayData()
Dim conn As OleDbConnection = New OleDbConnection(ConfigurationManager.ConnectionStrings("BookMeetConnString").ConnectionString)
Dim sql = "SELECT * FROM userprofiles WHERE TravellerName=#f1"
Dim cmd = New OleDbCommand(sql, conn)
cmd.Parameters.AddWithValue("#f1", User.Identity.Name)
conn.Open()
Dim profileDr = cmd.ExecuteReader()
profileDr.Read()
Dim newEmailAddress = ""
Dim newDescription = ""
If Not IsDBNull(profileDr("EmailAddress")) Then newEmailAddress = profileDr.Item("EmailAddress")
If Not IsDBNull(profileDr("Description")) Then newDescription = profileDr.Item("Description")
If Not IsDBNull(profileDr("AvatarURL")) Then ProfilePic.ImageUrl = profileDr.Item("AvatarURL")
description.Text = newDescription
email.Text = newEmailAddress
conn.Close()
End Sub
Rather than checking if a record exists in the 'userprofiles' table that matches the User.Identity.Name of the current user, I thought it would be easier just to evaluate whether or not the user had just been redirected from the Register.aspx page. (If this evaluation is true, then as you can see above, a separate "New User" function will be called).
That is my logic, but I have no clue if VB.NET has a "referrer" or "isReferred" expression? (at the minute as you can see I thought isCrossPagePostback might be the right thing but no luck!)
Any ideas?
You need to check whether or not a record exists and base your logic on that. That is the only right way to do it. As in:
What if you introduce a new page to handle registrations? This logic breaks.
What if you one day you retire and the next guy decides to rename the Register.aspx page? This logic breaks.
What if user hits back button and clicks the Register button again? This logic may break.
You should also consider a foreign key and unique constraint on that table, as well as using UserId instead of TravellerName. TravellerName can change, UserId will not.
... and yes you can the referring page by using HttpRequest.ServerVariables, which gets you a list of IIS Server Variables.

How do I populate multiple textboxes based on value of another textbox or dropdownlist?

hello again.
We have a webform that employees use to make request for such things as VPN access to the company resources from remote locations.
I am populating a dropdownlist box from Active Directory. This works fine.
Then I have a textbox that is also populated from Active Directory by simply assigning the value of the logged in user as shown:
textbox1.Text = User.Identity.Name
Based on the value of my name assigned to textbox1.Text
The rest of the texboxes are populated with my work information with the following code:
textbox1.Text = User.Identity.Name
textbox1.Text = StrConv(textbox1.Text, vbProperCase)
txtdate.Text = DateTime.Now.ToString("MM/dd/yyyy")
Try
'Creates a Directory Entry Instance with the Username and Password provided
Dim deSystem As New DirectoryEntry("LDAP://OU=Departments,DC=domaname, DC=com", "usrname", "password")
'Authenticacion type Secure
deSystem.AuthenticationType = AuthenticationTypes.Secure
'Creates a Directory Searcher Instance
Dim dsSystem As New DirectorySearcher(deSystem)
'sAMAccountName is equal to our username passed in.
dsSystem.Filter = "sAMAccountName=" & textbox1.Text
'Properties that the Procedures will load from Active Directory
dsSystem.PropertiesToLoad.Add("mail") 'email address
dsSystem.PropertiesToLoad.Add("department") 'dept
dsSystem.PropertiesToLoad.Add("physicalDeliveryOfficeName") 'office
dsSystem.PropertiesToLoad.Add("title") 'title, eg programmer1
dsSystem.PropertiesToLoad.Add("telephoneNumber") 'phone
dsSystem.PropertiesToLoad.Add("streetAddress") 'street address
dsSystem.PropertiesToLoad.Add("l") 'city
dsSystem.PropertiesToLoad.Add("st") 'state
dsSystem.PropertiesToLoad.Add("postalCode") 'zip code
dsSystem.PropertiesToLoad.Add("EmployeeId") 'empid
dsSystem.PropertiesToLoad.Add("givenName") '//first name from active directory
dsSystem.PropertiesToLoad.Add("sn") '//lastname from active directory
'Find the user data
Dim srSystem As SearchResult = dsSystem.FindOne()
'Obtains the properties recently loaded
txtemail.Text = srSystem.Properties("mail").Item(0).ToString
dept.Text = srSystem.Properties("department").Item(0).ToString
office.Text = srSystem.Properties("physicalDeliveryOfficeName").Item(0).ToString
txttitle.Text = srSystem.Properties("title").Item(0).ToString
phone.Text = srSystem.Properties("telephoneNumber").Item(0).ToString
workaddress.Text = srSystem.Properties("streetAddress").Item(0).ToString
city.Text = srSystem.Properties("l").Item(0).ToString
state.Text = srSystem.Properties("st").Item(0).ToString
zipcode.Text = srSystem.Properties("postalCode").Item(0).ToString
hiddenempId.Value = srSystem.Properties("EmployeeId").Item(0).ToString
HiddenFName.Value = srSystem.Properties("givenName").Item(0).ToString
HiddenLName.Value = srSystem.Properties("sn").Item(0).ToString
This works fine as well.
Here is where my problem lies.
Initially, when the user logs in, based on logged user name from Active Directory, the rest of the textboxes get populated with the user's info.Sorry for repeating myself here.
However, sometimes, the user logged in is not necessarily the user needing reguest.
In other words, I can log in to fill a request for another employee.
In this case, I am required to select the name of the user I am completing the request for from the dropdownlist that is populated from Active Directory.
When I select this name from dropdownlist, it replaces my own name on textbox1.Text.
This works fine but the rest of the textboxes retain my own information.
What do I need to do to ensure that the name that replaces my original name on textbox1.Text also replaces the information on the rest of the textboxes?
I will post additional information as requested.
Many thanks in advance
Instead of loading all the text boxes when the form loads, load them from the TextChanged event of the user name text box. That way, any time the user name text box changes, all the other text boxes will automatically be re-loaded to reflect the change.

What is happening when ASP.NET MVC 3 Accounts Scaffolding calls Membership.Createuser?

I am an asp mvc 3 noob trying to modify the user account scaffolding to hold more information. When users create an account, I want to add additional information like their full name and start date--not just their username/pw. I am going to store this added info in an Employees table in the DB.
I see the line of code in the AccountController that creates the account after the user types in input to the form.
Membership.CreateUser(model.UserName, model.Password, model.Email, Nothing, Nothing, True, Nothing, createStatus)
It seems like this line calls a stored procedure in SQL server. It seems like the most likely stored procedure is aspnet_Membership_CreateUser. But this stored proc has 13 parameters, and the code above passes 8 parameters.
What stored procedure is called by the VB code shown above (membership.createuser...)?
Why don't aspnet_Membership_CreateUser and Membership.CreateUser have the same number of parameters?
How do I modify the create user code/stored procedure to add employee information into the EmployeeTable based on info from the registration form, and then add a link between the user account and the Employee record? In general, the idea would be to add the employee info as additional parameters to the stored proc and then have the stored proc do the inserts/add the ids, but where exactly do I look to do this?
The code will run the aspnet_Membership_CreateUser stored procedure
The Membership.CreateUser is overloaded, and will put default values for parameters that would not have been provided. For example, if you call CreateUser with just the username and password, all the other parameters will be defaulted, e.g. IsApproved will be true. >>When typing in CreateUser, you should see the overload options. You can look at the code in "C:\Windows\Microsoft.NET\Framework\v4.0.30319\system.web.dll" using a tool like Just Decompile
There are different ways of storing additional data. Look at this one. I prefer linking the tables by UserId/Email address, and when creating a user, I call the CreateUser, and if its successful, then save the additional data (which is a slight variation of the method described in that tutorial). You can also modify/extend the whole membership provider, see this link (Implementing a Membership Provider) or this video tutorial
I can't answer your other questions, but here is the code I use the extend the user registration to contain more date (using a profile table, not the profile provider):
'
' POST: /Account/Register
<HttpPost()> _
Public Function Register(ByVal model As RegisterModel) As ActionResult
If ModelState.IsValid Then
' Attempt to register the user
Dim createStatus As MembershipCreateStatus
Dim MembershipUser = Membership.CreateUser(model.UserName, model.Password, model.Email, Nothing, Nothing, True, Nothing, createStatus)
If createStatus = MembershipCreateStatus.Success Then
Dim providerKeyObject = MembershipUser.ProviderUserKey
Dim providerKeyGuid = MembershipUser.ProviderUserKey
' update profile entity
Dim db As UserProfileDbContext = New UserProfileDbContext
Dim profile As New UserProfile
profile.UserId = providerKeyGuid
profile.IsCompanyOwner = True
profile.CompanyId = model.Company
profile.BlogId = model.Blog
profile.IsCompanyOwner = model.IsCompanyOwner
profile.IsBlogOwner = model.IsBlogOwner
db.UserProfiles.Add(profile)
db.SaveChanges()
FormsAuthentication.SetAuthCookie(model.UserName, False)
' send email
' TODO: fix error on send
Call New EmailController().VerificationEmail(model).Deliver()
Return RedirectToAction("Index", "Home")
Else
ModelState.AddModelError("", ErrorCodeToString(createStatus))
End If
End If
' If we got this far, something failed, redisplay form
Return View(model)
End Function

Resources