.Net 3.5 and Silverlight 2.0

I've been working on a Silverlight application with a colleague of mine (John Papa), and we wanted to create a secure login that would tell the hosting asp.net page to authenticate the user.  We looked at Tim Heuer's example and decided to go with a similar approach.  This basically involves hosting the WCF Authentication service in a web application, and then creating and using in Silverlight via a service reference.

The only issue is that Tim's approach uses the built in .NET membership provider which creates and uses a local SQL Express database.  Since the project I'm working on already has a database with user/pass information, I wanted to avoid creating a second database that would be used for nothing other than maintaining user and password info.  The solution to using your own database is to create a custom provider (i.e. inherit from the abstract class called System.Web.Security.MembershipProvider).  The amount of work required to do this depends on how much you need it to do for you.  If you want to be able to create your own users via the ASP.NET conifguration tool, you'll have to override and define many of the methods.  Since we only needed the very basic "Is this a valid user" scenario, it only involved defining two methods and one property.

public class MyMembershipProvider : MembershipProvider
{
    private string _connectionString;
    
    public override void Initialize(string name,
                    System.Collections.Specialized.NameValueCollection config)
    {
        _connectionString = config["connectionString"];
    }
    
    public override bool ValidateUser(string username, string password)
    {
        SqlConnection sqlConnection = new SqlConnection(_connectionString);
    
        try
        {
            sqlConnection.Open();
            string sql = "select Username from [UserTable] where Username=@User 
                    AND Password=@Pass";
    
            SqlCommand sqlCommand = new SqlCommand(sql, sqlConnection);
            sqlCommand.Parameters.AddWithValue("@User", username);
            sqlCommand.Parameters.AddWithValue("@Pass", password);
            SqlDataReader sdr = sqlCommand.ExecuteReader();
            if (sdr.HasRows)
                return true;
        }
        catch (Exception e)
        {
            throw e;
        }
        finally
        {
            sqlConnection.Close();
        }

        return false;    
    }

    public override string Name
    {
        get
        {
            return "MyMembershipProvider";
        }
    }    


    // override the rest below 
    ...
}
 

These are the main 3 things you need to override and define.  You must also override all of the other methods and properties, but for the ones you don't need, you can just throw a NotImplementedException() and leave it undefined.  You will want to change the code in ValidateUser() method to either use a stored procedure or change the SQL code to work with your table. 

The next step is to make your web application use this rather than the default provider.  In order to do this, you must add the following to your web.config within the <system.web> opening and closing tags.  You will need to make sure you set authentication mode to forms as shown below, and then add the <membership> tags

<authentication mode="Forms"/>

<membership defaultProvider="MyMembershipProvider">
    <providers>
        <add name="MyMembershipProvider" type="YourNamespace.MyMembershipProvider"
                connectionString="Data Source=(local)\SQLExpress;
                                  Initial Catalog=YourDB;
                                  Persist Security Info=True;
                                  User ID=test;Password=test" />
    </providers>
</membership>

Obviously, you will name your MembershipProvider something other than "MyMembershipProvider", and you will have to provide your own ConnectionString.

Before being able to access this via Silverlight, you'll want to test it.  The easiest way to test it is to use the asp.net Login control.  Since we defined our web.config to use our provider, the Login control will use our ValidateUser() method.  In a webpage, throw a simple asp.net Login control onto a page, so that the aspx page looks like this:

<div>
    <asp:Login ID="Login1" runat="server" DestinationPageUrl="~/HomePage.aspx">
    </asp:Login>

</div>

This is all you'll need to test it.  Place some breakpoints in your membership provider to make sure that it's being used. If everything works, you'll be ready for the next step.

Once you've verified it works, you are set to follow Tim Heuer's approach.  In your web project, you will want to add a new folder and call it Services.  Inside of that, add a new blank text file and call it Auth.svc.  Add the one and only line of text:

<%@ ServiceHost Language="C#" Service="System.Web.ApplicationServices.AuthenticationService" %>  

Follow the rest of Tim Heuer's example to edit the web.config file and create the service reference: Tim Heuer's Example

I have provided a sample application that does the entire process.  Click here to download