This article attempts to work out an example of the impersonation namespace in .NET, to logon a user through a webpage, with his Windows logon credentials. The traditional way of logging in users using their Windows authentication is by enabling the Basic Authentication property of the web application in IIS.
But, using the control, we can eliminate the necessity of controlling logon through IIS, and enable it through our code. This opens up a considerable area of control through code. We can hence have a control on which user login is requested, and on which domain and all that.
We will discuss the creation of the project and the logic I had in mind while developing it. The completed and tested code, that was developed using VS.NET is attached to this article.
We create two web user controls.
This has the implementation and UI for the login pane. It has two UIs, one for new users, one for already logged in users. A session variable maintains the state of the login to determine which UI to show. Code in this control calls the
logInUser class' shared method to process the login.
This has implementation and UI for an error reporting pane. When errors occur, other controls on the page update a session variable, which is checked when this control loads. When there's no error, we display an 'Under construction' message (This may be removed in release versions).
NOTE: We could have implemented the logic of this control also into the
WindowsLoginControl, but having this as a separate control allows us to easily move the control on the UI of a target page in VS.NET.
LoginUser class with a shared method for processing the login,
This has implementation of the login process. A shared method takes username, password and domain as parameters and tries a Windows logon with the data, and we impersonate the user.
- A logoff page which clears user's session and abandons it.
This is to cleanup the sessions, and make the
totalActiveUser count on the system more reliable.
Open an ASP.NET project. Select the project in the Solution Explorer and create a new 'web user control' item. Develop the UI for it.. probably two text boxes.. for username and password and a 'Login' button.
We make another UI, which shows a viewpane with the details of user login.
We show the login form when the user hasn't logged into the system, and show a login details view after the user logs in. Users login with their Windows authentication (this means that we should have created users on the server and the domain for this to work).
windowsLoginControl calls shared function
LogInThisUser() of the
LogInUser class which logs-in the user and impersonates the logged-on user. The code that does this is as below.
Dim loggedOn As Boolean = LogonUser(username, _
domainname, password, 3, 0, token1)
Dim token2 As IntPtr = New IntPtr(token1)
Dim mWIC As WindowsImpersonationContext = _
For this, we declare the
loginuser class with the proper namespaces, and in a manner to include unmanaged code. We need unmanaged code to be written, because I believe we don't have a managed code implementation of the
LogonUser function of Windows to do the same.
Public Class LogInUser
Private Shared Function LogonUser(ByVal _
lpszUsername As String, ByVal lpszDomain _
As String, ByVal lpszPassword As String, _
ByVal dwLogonType As Integer, _
ByVal dwLogonProvider As Integer, _
ByRef phToken As Integer) As Boolean
Private Shared Function GetLastError() As Integer
We can also find whether the
logonuser function generated errors, by calling the
We use session variables to keep track of the user's login information and last access. We use an application variable to keep track of the total active users in the system.
Below code is a part of this implementation (can be found in windowsLoginControl.ascx.vb)
Application.Item("TotalActiveUsers") += 1
lblUserName.Text = Session("Username")
lblLastSession.Text = Session("LastActive")
lblTotalUsers.Text = Application("TotalActiveUsers")
We keep track of the no. of active users by simply incrementing the value every time the login method succeeds, and decrementing the value every time
session_end event occurs.
Better means to do this can also be used. The idea of this article is only to communicate the logic.
Testing the project
Before testing the project, we should check the following.
We keep the
domainname as constant, rather than taking it from the user as an input. Check whether proper domain name is assigned to the constant.
Private Const domainName = "TestDomain"
Check whether location of the DLLs that are being imported are proper.
Check whether the logoff page has the correct page name and path to transfer the user, once cleanup is done.
It has to be taken care that code implemented doesn't allow for inappropriate usage through various
I preferred to keep the domain name hard-coded into the application through a constant rather than accept it as an user input... so that it's easy to limit or monitor user login sessions.
In case of intranet projects, we can create a separate domain, and user group for the project and use the above logic to allow users to login to the system only on the particular domain. May be you can call this an 'Idea' :o)
Using the controls on another web project
To implement the web user controls in a web project, we simply copy the files related to the two controls, the
loginuser class, the logoff user page, to our new web project, and also copy the code from our global.asax.vb to the new project's global.asax.vb.
In VS.NET, these copied files can easily be included in the target project by right clicking and selecting 'Include in Project' in Solution Explorer.
The code that's been worked out in this article will authenticate users on only one page of the web application. Normally, a web application will have content inside the site to be viewed by authenticated users.. in this case, the controls will have to have a mechanism of holding the user's authentication across page requests. This can be done by holding the
windowsIdentity object of the authenticated user in a session variable, and allowing users rights on pages by using
FileIOPermission and other classes in the