CIS Logo SVC Logo

   Computing & Information Systems
   Department

 

Schoology Facebook        Search CIS Site      Tutorials

A Web App Requiring Login



The Goals for this Example


The overall goal is to show how access to a page or to a folder of pages can be protected by requiring users to login with a username and password. We will use what is called forms authentication. Before we get to the main example, we do a couple of easy ones to build up to the main one.

Simple Examples



First Easy Example

  • Since setting up forms authentication requires a change to your Web.config file, make a new website in Visual Studio, placing it on your W drive (or some other convenient location if you do not have a drive that maps to a location with the web root on your live web server). Name this web site Logon1.
  • Add 2 forms to your website: Default.aspx and Login.aspx.
  • To make this example quick to do, all of the code will be provided.
  • Change to source view in Default.aspx and copy the following code over the head and body sections.

<head runat="server">
    <title>Protected Application</title>
</head>
<body style="height: 72px">
    <form id="form1" runat="server">
    <div style="height: 61px">   
        <asp:Label ID="Label1" runat="server" style="z-index: 1; left: 41px; top: 37px; position: absolute" 
            Text="Protected Application"></asp:Label>    
    </div>
    </form>
</body>

  • Look at Default.aspx in design view. Note that it is a very simple page. We are going to leave it very basic like this so that we can concentrate on requiring a login in order to access this trivial page.
  • Open Login.aspx and look at it in source view.
  • Copy the following code over the head and body sections.

<head runat="server">
    <title>Login Page</title>
</head>
<body style="height: 284px; width: 318px">
    <form id="form1" runat="server">
    <div style="height: 272px">
        <asp:Label ID="Label1" runat="server" Text="Username:"
            style="z-index: 1; left: 29px; top: 53px; position: absolute"></asp:Label>
        <asp:Label ID="Label2" runat="server" Text="Password:"
            style="z-index: 1; left: 31px; top: 119px; position: absolute"></asp:Label>
        <asp:Button ID="LoginButton" runat="server" Text="Login"
            style="z-index: 1; left: 107px; top: 190px; position: absolute; width: 49px;" />
        <asp:TextBox ID="UsernameTextBox" runat="server"
            style="z-index: 1; left: 124px; position: absolute; top: 48px"></asp:TextBox>
        <asp:TextBox ID="PasswordTextBox" runat="server" TextMode="Password"
            style="z-index: 1; left: 127px; top: 118px; position: absolute"></asp:TextBox>
        <asp:Label ID="ErrorLabel" runat="server" Text="Invalid credentials"
            style="z-index: 1; left: 78px; top: 242px; position: absolute" Visible="False"></asp:Label>
    </div>
    </form>
</body>

  • Look at Login.aspx in design view so that you can more easily see the layout of the textboxes for the username and password, the login button, and the ErrorLabel (which will be kept invisible unless an error occurs).
  • Changes are also needed in your Web.config file. Open that file and copy the following over the top of the existing configuration section.

<configuration>
    <system.web>
        <authentication mode="Forms">
            <forms name="Login1" loginUrl="Login.aspx" path="/">
            </forms>
        </authentication>
        <authorization>
            <deny users="?" />
        </authorization>
        <compilation debug="false" strict="false" explicit="true" targetFramework="4.5" />
        <httpRuntime targetFramework="4.5" />
    </system.web>
</configuration>

  • Note that the authentication section says that the mode is Forms. This means forms authentication is the method used.
  • The name of Login1 is used as the name of the cookie that is saved in order to remember that this particular user is currently logged in. By default the app uses both data validation and encryption to protect this cookie.
  • The loginUrl is the name of the page to go to if the user has no cookie indicating that this user is already logged in.
  • The path indicates where the cookie should be stored. Usually you want /, which is the default value.
  • By default, the cookie expires in 30 minutes, but this can be changed by adding an entry such as timeout="60" into the forms tag. That particular change would give 60 minutes.
  • In the authorization section, the deny users="?" means that all anonymous users (users who are not logged in) are denied access to the protected page, Default.aspx in this example. Instead, anonymous users who try to go to Default.aspx get redirected to Login.aspx, where they will be asked to log in.
  • On the Login.aspx page, in design view, double click on the button in order to get the outline of a click handler for that button. Make the code for the click handler look like the following.

Protected Sub LoginButton_Click(sender As Object, e As EventArgs) Handles LoginButton.Click
    If (UsernameTextBox.Text = "carlsond" And PasswordTextBox.Text = "easy123") Then
        FormsAuthentication.RedirectFromLoginPage(UsernameTextBox.Text, False)
    Else
        ErrorLabel.Visible = True
    End If
End Sub

  • Note that this VB code contains the username carlsond and the password easy123 in clear text. This is a very bad idea from a security point of view, but gives an easy example as a starting point.
  • If the username and password supplied by the user both match what is in the VB code, the RedirectFromLoginPage sends the user to the page the person had tried to reach, here Default.aspx. The user is now logged in.
  • If the login does not succeed, due to a mismatch in the usernames and/or passwords, the error label is made visible and the user still has no access to Default.aspx.
  • The first parameter to RedirectFromLoginPage is the name of the user.
  • The False as the second parameter to RedirectFromLoginPage says that a durable cookie is not used. If set to True, the user would not have to log in again after closing the app and starting it up again. False is the more secure setting.
  • Save your files and build your web app in the usual way.
  • Then run it, either locally or on the live web server. Your URL should look something like mine: http://cis2.stvincent.edu/carlsond/Logon1/. Since no aspx page was mentioned, it means that I want to access the default page in the Logon1 folder, namely Default.aspx.
  • You should be sent instead to the Login page, where you are asked for a username and password.
  • If you look carefully at the URL your browser has at this point, you will see that it has changed to something like: http://cis2.stvincent.edu/carlsond/Logon1/Login.aspx?ReturnUrl=%2fcarlsond%2fLogon1%2f
  • This indicates that if login succeeds, the user should be sent to /carlsond/Logon1/ on the web server. Without a mention of a particular file in that Logon1 folder, this means to send the user to Default.aspx in that folder.
  • Check to see that you get to the Default.aspx page when you login with the username and password given in the code above.

Second Easy Example

  • The plan in this one is to move the username and password from the VB code to your Web.config file.
  • You can either modify your website from the first example above or make a copy of it and work on that copy.
  • Thus you will have the same two forms: Default.aspx and Login.aspx.
  • No changes are needed in the Default.aspx and Login.aspx forms themselves.
  • Change your Web.config file's configuration section to match the following.

<configuration>
    <system.web>
        <authentication mode="Forms">
            <forms name="Login1" loginUrl="Login1.aspx" path="/">
                <credentials passwordFormat="Clear">
                    <user name="carlsond" password="easy123"/>
                </credentials>
            </forms>
        </authentication>
        <authorization>
            <deny users="?" />
        </authorization>
        <compilation debug="false" strict="false" explicit="true" targetFramework="4.5" />
        <httpRuntime targetFramework="4.5" />
        <customErrors mode="Off"/>
    </system.web>
</configuration>

  • The <customErrors mode="Off"/> is optional, but you may want to include it so that you can see detailed error messages in case anything goes wrong.
  • We have already discussed what most of this means.
  • The new item is the credentials section, which obviously contains the username and password (or several username/password pairs) within it.
  • The value of Clear for passwordFormat indicates that passwords are stored in plain text in Web.config and that passwords that users supply at the Login page will be compared against this plain text.
  • This is not the most secure way to handle usernames and passwords.
  • Next, we need to get the username and password out of the VB file. Change your Login.aspx.vb file so that its click handler looks like the following.

Protected Sub LoginButton_Click(sender As Object, e As EventArgs) Handles LoginButton.Click
    If FormsAuthentication.Authenticate(UsernameTextBox.Text, PasswordTextBox.Text) Then
        FormsAuthentication.RedirectFromLoginPage(UsernameTextBox.Text, False)
    Else
        ErrorLabel.Visible = True
    End If
End Sub

  • The Authenticate function provided by FormsAuthentication is used here to check that the text the user supplied in the textboxes for the username and password matches (or does not match) the text in the Web.config file.
  • If these match, RedirectFromLoginPage is used (as in the first example above) to send the user to the page the person was tring to reach in the first place. That would be Default.aspx in this case.
  • If one or both of the username and password does not match what is in the Web.config file, all that happens is that the ErrorLabel is made visible.
  • Visual Studio will probably warn you that this Authenticate function is obsolete. The warning you get says that the recommended alternative is to use the Membership APIs, such as Membership.ValidateUser, and that you can go to http://go.microsoft.com/fwlink/?LinkId=252463 for further information. You might want to try this, but it could take a fair amount of time to learn your way around the Membership APIs.
  • Another possible improvement is to store password hashes in Web.config, not clear text passwords. Either MD5 or SHA1 hashes can be used. These hashes can be produced by using something such as FormsAuthentication.HashPasswordForStoringInConfigFile(TextBox1.Text, "MD5"). You would have to write yourself a little app that uses this function to produce the password hashes and store them in Web.config (exactly where we currently have the plain text passwords). This is the only change needed; the use of the Authenticate function stays exactly the same. In other words, the Authenticate function is smart enough to hash the plain text password supplied by the user in order to compare it with the stored and hashed password in Web.config.
  • Before doing either of these improvments, if you do them at all, build your app and check that it does indeed protect Default.aspx by requiring login with username and password.

Main Example



Goals

  • The main goal is to move the usernames and passwords to your SQL Server database. This is a safer place to keep them, though, once again, it would be even better to store just hashes of the passwords and not the plain text passwords.
  • We also will build a simple application that is protected by the login process. This application will allow the user to view all of the data from your Parts file. We assume, for the sake of this example, that this data is somewhat confidential and that we want to password-protect the web access to this data. This example will also provide a logout button.
  • See this screen shot of the app displaying the Parts data.

Database Changes

  • In SQL Management Studio, add a new table to your database. It should have 2 columns, Username and Password, having types varchar(12) and varchar(16) respectively. Username should be marked as the primary key as usernames need to be distinct.
  • Name your table Users.
  • Add a couple of simple usernames and passwords for testing purposes.
  • If you do not have a Parts table, add one as in this previous example.

The Forms and Web.config

  • You can again modify your previous website, used for the 2 simple examples above, or copy it and work on the copy.
  • The Login.aspx page should remain the same.
  • Default.aspx should be changed to give the functionality shown in the above screen shot.
  • Besides the controls that you see in that screen shot, also place a label with ID ErrorLabel to the right of the buttons. Make the text property say "Error in submitting data" and set the Visible property to False.
  • Your Web.config file should be modified to appear like that shown in the box below. More will be added to it as you go through the rest of this example. Note that you have to copy in your web app connection string from one of your earlier database-related web apps. You might also want to copy in the connection string for your own Windows account, but for your web app to work on the separate, live web server, your app must use the web app connection string.

<configuration>
    <system.web>
        <authentication mode="Forms">
            <forms name="Login" loginUrl="Login.aspx" path="/" />
        </authentication>
        <compilation debug="false" strict="false" explicit="true" targetFramework="4.5">
        </compilation>
        <httpRuntime targetFramework="4.5" />
        <customErrors mode="Off" />
    </system.web>
    <location path="Default.aspx">
        <system.web>
            <authorization>
                <deny users="?" />
            </authorization>
        </system.web>
    </location>
    <connectionStrings>
        The actual connections strings are not shown. You need to copy in your webapp connection string.
    </connectionStrings>
</configuration>

  • Note that you have to copy into your Web.config file your web app connection string from one of your earlier database-related web apps. You might also want to copy in the connection string for your own Windows account, but for your web app to work on the separate, live web server, your app must use the web app connection string.
  • The authentication section of this Web.config file is like what you used in the simple examples above.
  • Note, however, the new location section and where it is placed: outside of the system.web section.
  • The path="Default.aspx" indicates that we are protecting the Default.aspx file. Supposedly you can replace this Default.aspx name with the name of a subfolder so as to protect all of the files in that subfolder, if you wish to do that.
  • You can have more than one location section if there is a reason for you to do so.
  • Our text's method of handling the location section does not seem to work with the Windows forms authentication example we are working on here, so stick to what we have on this web page.

Create the Database Models

  • Yes, that is plural. We will create 2 models, one for the User table which will be used by Login.aspx.vb and one for the Parts table which will be used by Default.aspx.vb.
  • As you have done before, generate a database model by right clicking your App_Code folder and making the usual choices.
  • For the first model, use the names UsersModel, usersEntities, and UsersNamespaceModel or similar. Be careful to remember the second name, usersEntities, as you will need to use it in your VB code.
  • Only select the Users table from among the tables in your database.
  • After that first model has been created, make a second one. This one should be for just the Parts table. Name the three items PartsModel, partsEntities, and partsNamespaceModel or similar. Again, you will need to use the second of these in your VB code later.
  • Save everything, close Visual Studio, and then reopen it a bit later. This seems to be needed for Visual Studio to recognize the new items usersEntities and partsEntities.

The Code for Login.aspx.vb

  • Use the Entity Framework and LINQ to select the Username and Password from the Users table where the Username matches with the text found in the username textbox on the Login.aspx form.
  • Follow that by an IF test that checks to see if the passwords match. Note that in the data obtained with LINQ you will have to use FirstOrDefault on it as the data returned is a collection. We want just the first (and hopefully only) entry in this collection. Of course, for this first entry, pick out the Password field.
  • If the passwords matched, then use FormsAuthentication.RedirectFromLoginPage as above to send the user to the page originally requested, which here again is Default.aspx.
  • Use the following outline to get started. See if you can finish the code on your own. If you get stuck, ask your instructor for assistance.

Sub LoginButton_Click(sender As Object, e As EventArgs) Handles LoginButton.Click
    Try
        The usual Using statement goes here for your entities. 
            Dim userMatch = Here place the LINQ to retrieve from the Users table the Password and Username where
               the Username matches what's in the username textbox on the form.
            If PasswordTextBox.Text = userMatch.FirstOrDefault.Password Then
                FormsAuthentication.RedirectFromLoginPage(    ,    )   Fill in the parameters as above.
            Else
                ErrorLabel.Visible = True
            End If
        End Using
    Catch exception As Exception
        ErrorLabel.Visible = True
    End Try
End Sub

The Code for Default.aspx.vb

  • Use the Entity Framework and LINQ to select all of the data from the Parts table.
  • Then display the data in the grid view that you placed on the Default.aspx form.
  • Use the following outline to get started. See if you can finish the code on your own. If you get stuck, ask your instructor for assistance.

Protected Sub ViewDataButton_Click(sender As Object, e As EventArgs) Handles ViewDataButton.Click
    Try
        Use the entity framework and LINQ in the usual way to retrieve all of the data from your Parts table.
        Then display that data in your grid view on the Default.aspx page.
    Catch exception As Exception
        ErrorLabel.Visible = True
    End Try
End Sub

Protected Sub LogoutButton_Click(sender As Object, e As EventArgs) Handles LogoutButton.Click
    FormsAuthentication.SignOut()
    FormsAuthentication.RedirectToLoginPage("Login.aspx")
End Sub

  • Note that the above box simply gave you the code for the LogoutButton click handler.
  • The SignOut function removes the cookie that the user authenticates with. Thus any new access to the protected page (or pages) is prevented.
  • The RedirectToLoginPage sends the browser to the Login.aspx form in case the user might want to log in again.
  • This Logout button is not completely satisfying as the user can still click the back button of the browser to go back to the page showing the displayed Parts data.
  • However, once logged out, the user cannot go to a new page (or pages). Sure, the stale data is still there, but if there were a second protected page, the person could not go there. If the user clicks on the View Data button again, when the reply comes back from the server it will send the browser to the login page instead of displaying the Parts data afresh. Try that yourself once you build and run your app to see that this happens.

Final Items

  • Save your files, build your web site, and then try it out, both locally and then on our live web server. For the latter, you will as usual have to have your folder converted to an IIS web app by whoever runs your web server.
  • While asking this person for assistance, also ask the person to have IIS require the use of SSL to access this web app. Since we are using plain text passwords (and usernames), it does not make sense to transmit these over the network unencrypted. Although this must be done by the web server administrator, for completeness, here are the steps needed:
    • In Internet Information Services (IIS) Manager on the server, find the user's web folder and the particular project within, the one that was just made an IIS web app.
    • Click on the web app folder and then double click on the SSL Settings icon.
    • Check the box labeled "Require SSL" and (for stronger encryption) check the "Require 128-bit SSL" box as well.
    • Under Actions, click on Apply.
  • This requires the use of SSL to encrypt any data flowing between the user's browser and the web server. In addition, it allows the user to view and accept the server's certificate.
  • This certificate's purpose is to verify that this server is the web server it purports to be, but the certificate is only as good as the organization that signed it. (For example, if that company was hacked, the certificate might not be legitimate.)
  • Now if you try to view your web app using the usual URL, such as:
    http://cis2.stvincent.edu/carlsond/Logon/
    you get a 403 Forbidden type of error message. The problem is that you must use SSL.
  • To access your web app you must now use https instead of http at the start of the URL, like this:
    https://cis2.stvincent.edu/carlsond/Logon/
  • The use of https gives you both encryption of data and access to the web server's certificate.
  • Normally this certificate would be signed by a recognized certificate authority and would be automatically accepted by your browser. If this certificate is not signed by a recognized certificatae authority, or if the certificate has expired, your browser should warn you. When using our own certificate (which is not one signed by a certificate authority), your browser will warn you about the certificate. Normally you should pay careful attention to this warning and not proceed to the website. (This is especially true when doing financial transactions online as a bad certificate could indicate that you are attempting to connect to a malicious website.) However, in this case, it is simply our own self-signed certificate on our departmental web server, so it is reasonable to tell your browser to go to the desired page or site. The option to do this may be labeled as "continue to this site (not recommended)" or "allow a temporary exception to access this site" or similar. You can probably also authorize a permanent exception for this certificate, but it is better not to do so. Seeing the certificate warning each time you access this site is a useful reminder.
  • Once the certificate is accepted, your browser displays the login page. At this point, some browsers may show a small padlock icon to indicate the secure connection. In the case of our app, you may see an error icon and/or an "invalid certificate" message that continues to warn you about the certificate.
  • If you turned on error reporting or debugging in your Web.config file, turn them off now. To return your Web.config file to normal (no debugging and no displaying of error messages in the browser), edit the file so that the customErrors and compilation sections look like what is shown in the box below. Note that either On or RemoteOnly for customErrors will protect users not on the same machine from the technical details of errors and protect your website from hackers who would like to see those detailed error messages!
  • An optional item to try, if you are interested, is to use a Login control in place of our textboxes and other primitive controls on the Login.aspx form. You can read about how the Login control works both online as well as in many books, including our textbook. These writeups may or may not show you how to use the Login control with usernames and passwords stored in a database on a different server. Often they show only simpler scenarios, such as having the usernames and passwords in the VB code itself or using a local database on the same server.

      <compilation debug="false" strict="false" explicit="true" targetFramework="4.5"/>
      <customErrors mode="On"/>


Back to the main page for ASP.NET 4.5 Web Apps



Author: Br. David Carlson
Last updated: October 18, 2017
Disclaimer