Writing A Custom Membership Provider for your ASP.NET 2.0 Web Site

 
ne feature introduced in ASP.NET 2.0 is the use of the "provider model" to provide maximum flexibility and extensibility to your Web applications. Using the provider model, developers can easily extend the capabilities provided by the ASP.NET 2.0 runtime, in many different ways. For example, you can extend the provider model to store the membership information for your Web site users in a custom data store, rather than the default SQL Server Express 2005 database.


To understand how the provider model works, consider the new Login controls in ASP.NET 2.0. The relationships between the Login controls and their underlying APIs are shown in Figure 1.
 
Figure 1. The Membership Provider Model: Everything involved in the use of the ASP.NET provider model is shown.

At the top level are the various Login controls themselves. Underlying the controls are the various APIs that perform the work needed to implement the functions of the various controls. The Membership class takes care of tasks such as adding and deleting users, while the MembershipUser class is responsible for managing users' information, such as passwords, password questions, etc. The Membership and the MembershipUser classes use one of the membership providers to save user information to data stores.

In Visual Studio 2005 (beta 2 as at this writing), ASP.NET 2.0 ships with one default membership provider—SQL Express Membership Provider. The role of the provider is to act as a bridge between the membership APIs and the membership data, so that developers need not be concerned with the details of data storage and retrieval. Think of the membership provider as a middle-man in charge of all communications between the APIs and the data.

However, if the provider supplied with ASP.NET 2.0 does not meet your needs, you can write your own custom provider. In this article, I will show you how to build a custom membership provider that uses an Access database (rather than the default SQL Express 2005 database) to store users' information. You can then adapt the concepts covered in this article to use any data source (such as Oracle database, XML files, or even plain text files) you want for your membership provider.

Creating the Project
As there are numerous controls in the Login controls family that use the membership provider, for simplicity I will only implement a subset of the features available in the membership provider. For this project, I will implement the:
  • CreateUser() function—this function is used by the CreateUserWizard control to allow users to register for a new account.
  • ValidateUser() function—this function is used by the Login control to allow users to authenticate themselves.
Using Visual Studio 2005 Beta 2, create a new Web site project using the Visual Basic language. Save the project as C:/NewMembershipProvider. Populate the Default.aspx Web form with the CreateUserWizard control (see Figure 2) and apply the Elegant scheme using the Auto Format link in the Smart tag of the control.

 


Figure 2. Setting it Up: The CreateUserWizard control is shown using the Elegant scheme, which quickly sets up a page to register a new user.
 
Figure 3. Log Services: The LoginView and LoginStatus controls are added to the AnonymousTemplate view in order to give the user a way to log in and out of the service.

Set the ContinueDestinationPageUrl property to "Login.aspx" so that when the user account is created, the user is redirected to the Login.aspx page(we will add this page shortly).

Also, add the LoginView control as shown in Figure 3 to the bottom of Default.aspx. In the AnonymousTemplate view of the LoginView control, add the LoginStatus control. The LoginView control allows you to display different messages depending on whether the user is authenticated (messages to display are set in the LoggedInTemplate view; see below) or not (messages are set in the AnonymousTemplate view). The LoginStatus control displays a hyperlink to redirect the user to a login page if he is not authenticated and allows the user to logout if he is authenticated.

In the LoggedInTemplate view of the LoginView control, type the message "You are logged in as" and add the LoginName and LoginStatus control as shown in Figure 4. The LoginName control will display the user's login ID.

 


Figure 4. Username View: Adding the LoginName and LoginStatus controls in LoggedInTemplate view will display the username of a logged in user.
 
Figure 5. Logging In: The Login.aspx page uses only the Login control, also with the Elegant scheme applied, to allow users who already have accounts to authenticate.

Next, add a new Web form to the project and name it Login.aspx. Add the Login control to the page (see Figure 5). Apply the Elegant scheme to the control.

Creating the Database
The custom provider you are building will save its data into an Access database. Therefore, you need to create an Access database. To maintain consistency with the location of databases in a typical ASP.NET 2.0 web application, save this database in C:/NewMembershipProvider/App_Data/. Give it the name Members.mdb.

Create a new table in the Members.mdb database and name it Membership. Define the table as shown in Table 1. :

Table 1. Fields for the Membership table of memers.mdb.

Field Name Data Type Field Size
Username (key)Text8
PasswordText8
EmailText50
passwordQuestionText50
passwordAnswerText50

Implementing Your Own Custom Provider
Before you learn how to implement your own custom provider, you need to understand the provider object model in ASP.NET 2.0. The default membership provider in Beta 2 is known as SqlMembershipProvider and it contains methods and properties specific to using SQL Express 2005 as a data store for membership information. It inherits from the MembershipProvider class, which provides data store-agnostic methods for storing membership information. The MembershipProvider class itself inherits from the ProviderBase class, the root of all providers (see Figure 6).

 
Figure 6. Providers: The provider model class hierarchy is shown.
If you just want to modify some of the implementations of the existing SQL membership provider (such as changing the way passwords are hashed or encrypted), then you simply need to create a class that inherits from SqlMembershipProvider and override the methods of concern, like this:


Public Class ModifiedSqlMembershipProvider
   Inherits SqlMembershipProvider

   Public Overrides Function CreateUser (...)
      ...
   End Function
   ...
End Class
However, if you do not want to use the SqlMembershipProvider supplied in Beta 2 (for example if you are creating your own custom data store for saving members' information, like using an Access database), then you need to implement your own class and inherit from the MembershipProvider class. The MembershipProvider class contains methods and properties for manipulating membership information, and when inheriting from this class you need to provide the implementation for all its methods and properties.

For simplicity, I will only provide the implementation for allowing users to register for a new account and to login to a Web site. For all of it, I will use the CreateUserWizard and Login controls.

Right-click on the project name in Solution Explorer and select Add New Item…. Select the Class template and name it as AccessMembershipProvider.vb. Click OK. You will be prompted to save the file in the App_Code folder. Click Yes.

First, import the System.Data namespace for database access:


Imports System.Data
Next, inherit from the MemberShipProvider class:

Public Class AccessMembershipProvider
   Inherits MembershipProvider

End Class
You will notice that Visual Studio 2005 will automatically add all the stubs for the methods that you need to override in the base class.

As the SqlMembershipProvider is the default provider used by the various security controls, you need to register the new membership provider you are creating in this article so that the ASP.NET runtime will now use your custom provider. To do so, add a Web.config file to your project (right-click on project name in Solution Explorer and select Add New Item…. Select the Web Configuration File template and click OK.


<system.web>
   <authentication mode="Forms"/>
   <membership 
      defaultProvider="AccessMembershipProvider" >
      <providers>
         <add name="AccessMembershipProvider" 
              type="AccessMembershipProvider"
              requiresQuestionAndAnswer="true"
              connectionString="Provider=Microsoft.Jet.
          OLEDB.4.0;Data Source=C:/NewMembershipProvider/
          App_Data/Members.mdb;Persist Security 
          Info=False" />
      </providers>
   </membership>
</system.web>
Note the following:
  • Authentication mode should be "Forms."
  • Add the new provider "AccessMembershipProvider" using the <add> element.
  • Specify the requiresQuestionAndAnswer attribute to "true" (you will see how this is used in later in this article).
  • Specify the connection string to the Access database in the connectionString attribute.
  • Specify the default membership provider as "AccessMembershipProvider" using the defaultProvider attribute in the <membership> element.
In general, you can specify any attribute name you like in the <add> element. The values of these attributes will be retrieved by the implementation of the provider ( AccessMembershipProvider.vb, in this case).

In AccessMembershipProvider.vb, add the following private member variables:


    '---for database access use---
    Private connStr As String
    Private comm As New OleDb.OleDbCommand

    Private _requiresQuestionAndAnswer As Boolean
    Private _minRequiredPasswordLength As Integer
Add the following Initialize() method:

Public Overrides Sub Initialize( _
   ByVal name As String, _
   ByVal config As _
    System.Collections.Specialized.NameValueCollection)

    '===retrives the attribute values set in 
    'web.config and assign to local variables===

   If config("requiresQuestionAndAnswer") = "true" Then _
       _requiresQuestionAndAnswer = True

   connStr = config("connectionString")
   MyBase.Initialize(name, config)
End Sub
The Initialize() method will be fired when the provider is loaded at runtime. The values specified in the attributes of the <add> element in Web.config will be passed into this method through the config parameter. To retrieve these attributes values, specify the config parameter using the name of the attribute, like this:

   If config("requiresQuestionAndAnswer") = "true" Then _
       _requiresQuestionAndAnswer = True

   connStr = config("connectionString")
In this case, I have retrieved the requiresQuestionAndAnswer and connectionString attribute values and saved them to the private variables declared earlier.

The requiresQuestionAndAnswer attribute value is used to set the RequiresQuestionAndAnswer property:


Public Overrides ReadOnly Property _
   RequiresQuestionAndAnswer() _
   As Boolean
    Get
        If _requiresQuestionAndAnswer = True Then
            Return True
        Else
            Return False
        End If
    End Get
End Property
It is important to set this property; if you don't, the password question and password answer textboxes will not be shown in the CreateUserWizard control (see Figure 7).

 
Figure 7. Question and Answer: If you don't set the RequiresQuestionandAnswer property the CreateUserWizard control will display without the password question and answer textboxes.
The CreateUserWizard control will invoke the CreateUser() method when the user clicks on the Create User button, so the next step you need to perform is to code this method (see Listing 1).

In this method, you can perform all the checks to ensure that the user has entered all the necessary information, such as the minimum number of characters for the password, to ensure that the password question and answer are supplied, etc. Once all these data are available, you can proceed to add the user information to your own custom data store—an Access database, in this case.

If the creation of the user is successful, you need to return a MembershipUser object. You also need to return the status of the creation through the status parameter (passed in by reference (ByRef)).

To ensure that the Login control validates user login through your custom database, you also need to implement the ValidateUser() method:


Public Overrides Function ValidateUser( _
   ByVal username As String, _
   ByVal password As String) As Boolean

    Dim conn As New OleDb.OleDbConnection(connStr)
    Try
        conn.Open()
        Dim sql As String = _
           "Select * From Membership WHERE " & _
           "username=@username AND password=@password"
        Dim comm As New OleDb.OleDbCommand(sql, conn)
        comm.Parameters.AddWithValue("@username", _
                                       username)
        comm.Parameters.AddWithValue("@password", _
                                       password)
        Dim reader As OleDb.OleDbDataReader = _
           comm.ExecuteReader
        If reader.HasRows Then
            Return True
        Else
            Return False
        End If
        conn.Close()

    Catch ex As Exception
        Console.Write(ex.ToString)
        Return False
    End Try
End Function
 
Figure 8. Registering: This is the UI for creating a new user account.
The ValidateUser() method is fired when the user clicks on the Log In button in the Login control. Here I basically retrieve any record that matches the supplied username and password. If there is at least one record, then the login is successful and the function returns a "true" value.

Testing the Application
That's it! Press F5 to test and debug the application. Figure 8 shows what happens when you try to register for a new user account.

Once the account is created, click on the Login hyperlink to test the new account. If you are successfully authenticated, you should see the login name (in my case it is "weimeng") used to login to the site (see Figure 9).

 
Figure 9. Logging In: This is the UI for logging in to the site using an existing username/password combination.

To verify that you are actually using the new membership provider, open the Access database and check that the user account is present in the table.

In this article, you have seen that creating your own custom provider is not a very difficult task. Creating a custom provider allows you to choose the best solution for your application, without being restricted to what is available. And this is precisely the design goal of the ASP.NET team—make Web development easy and at the same time extensible.

 

 

http://www.devx.com/asp/Article/29256#codeitemarea

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值