ASP.NET Providers - Membership
This blog post is part of a series about the ASP.NET Providers (namely Membership, Role Management, and Profile). The introductory post in the series can be found at the following link, which introduces the Provider Model pattern and gives a personal example of an implementation I have been working on:
This post will deal with adding the Membership functionality to your website.
Membership Provider Configuration
Now that your DB is set up, there are a few snippets that need to be added to your Web.config. It involves adding a connection string and adding a new membership provider, as in the sample below:
<configuration>
<connectionStrings>
<add name="MyDB" connectionString="..." />
</connectionStrings>
<system.web>
... authentication & authorization settings ...
<membership defaultProvider="ConfiguredMembershipProvider">
<providers>
<add name="ConfiguredMembershipProvider"
type="System.Web.Security.SqlMembershipProvider"
connectionStringName="MyDB"
applicationName="SampleWebSite"
minRequiredPasswordLength="5"
minRequiredNonalphanumericCharacters="0" />
</providers>
</membership>
</system.web>
</configuration>
WARNING: According to Microsoft, you should never use the default provider settings and should always add a new, configured provider; in addition you must be sure to specify the applicationName attribute! See Scott Guthrie’s blog post on this topic for more details. Apparently, you can also use a value of "/" for the applicationName and it will use the root application name.
The last two attributes of the add node are only a couple of several membership features you can configure. For a complete list of attributes you can configure, see <add> Element for Providers for Membership.
Securing Site Content by Requiring Authentication
With 5 more lines of configuration added to your Web.config, you can have the whole site secured and accessible only by user account authentication. Even better, you can make that 6 lines added to the Web.config, add a Login.aspx page, and drop in a Login control from the Toolbox and you will get auto-redirect to the login page if someone tries to hit any page you’ve now secured. The framework is even smart enough to return you to that desired page after successful login; it accomplishes this by redirecting you to the login page but by adding a ReturnUrl query string attribute to know where to go after authentication.
Here are the additional lines for your Web.config (put them under the system.web node):
<authorization>
<deny users="?" />
</authorization>
<authentication mode="Forms">
<forms defaultUrl="index.html" loginUrl="Login.aspx" />
</authentication>
NOTE: You will likely already have an authentication node in your Web.config, but it’s mode may be set to the default "Windows" value. To use the Membership Provider for authentication, you must have this value set to "Forms."
The optional 6th line I spoke of earlier is the forms node under the authentication node. The defaultUrl attribute of this line is used to tell the framework where to go after successful login if there is no ReturnUrl specified in the query string. The loginUrl attribute is used to specify the page the user is redirected to if they are attempting to hit a page that requires authentication.
The deny node is using the question mark (?) wildcard character, which is used for anonymous users (or those that haven’t been authenticated yet); the asterisk (*) wildcard is used to signify all users browsing the site. Since we are dealing with the Web.config at the root of the site, this deny rule will apply to the whole site and it’s subdirectories. You can either put a Web.config in each subfolder that requires an overriding or more restrictive set of allow and deny rules, or you can actually specify location elements in your Web.config, as is shown in the following example (basically you could have several of these location elements, each with their own authorization rules):
<configuration>
<location path="Login.aspx">
<system.web>
<authorization>
<allow users="?" />
</authorization>
</system.web>
</location>
</configuration>
As far as I can tell, this sample configuration above isn’t necessary if you have specified your login page in the loginUrl attribute of the authentication/forms node like we did in the previous code snippet. But this sample is at least illustrative of the location-based authorization rules.
Personally, I decided to create a folder named Public in my site and I give it its own Web.config that allows all users (including anonymous ones) access to the containing web pages. This folder currently contains the login, user account registration, account activation (a link included in the email sent upon registration), and password retrieval pages, all of which would need unrestricted access for anonymous users.
Test Your Membership Provider
With all of this now in place, you should be able to use the ASP.NET Website Administration Tool launched from Visual Studio to create a few new user accounts. I mentioned how to launch this utility earlier in this series with a post titled ASP.NET Providers - Getting Started. Then you can double-check your membership system is working by logging in with your newly created credentials. Also, you can now create a user account registration page (utilizing the CreateUserWizard control) and a password retrieval/reset page (using the PasswordRecovery control). All of the controls I have named throughout this post are highly skinable and configurable via numerous attributes and templates; they also contain flexible task workflows that you can override or plug into by registering to any of several event listeners.
One other thing that needs to be done if you want to enable the email notification capabilities is to set the SMTP settings in your Web.config. Here is a snippet you would put right above the system.web node:
<system.net> <mailSettings> <smtp from="service@website.com"> <network host="mail.domain.com" port="25" userName="..." password="..." /> </smtp> </mailSettings> </system.net>
Membership API and MembershipInfo Class
There is also a Membership API and an accompanying MembershipInfo class that you can call in order to retrieve and update user info from the database if you wanted to create your own custom controls or page logic. For instance, the following is code that I adapted from Part 11 of the tutorial I mentioned earlier in the introductory post of this series; this code activates an account when a user clicks the link emailed to them during registration:
public partial class Verify : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
//Make sure valid querystring value was passed
if (string.IsNullOrEmpty(Request.QueryString["ID"]) ||
!Regex.IsMatch(Request.QueryString["ID"],
@"[0-9a-f]{8}\-([0-9a-f]{4}\-){3}[0-9a-f]{12}"))
{
InformationLabel.Text = "An invalid ID value was passed " +
"in through the query string.";
}
else
{
//ID exists and is kosher, approve user
//Get the ID sent in on query string
Guid userId = new Guid(Request.QueryString["ID"]);
//Get user object
MembershipUser userInfo = Membership.GetUser(userId);
if (userInfo == null)
{
//Could not find user!
InformationLabel.Text = "The user account could not " +
"be found in the membership database.";
}
else
{
//User is valid, approve them
userInfo.IsApproved = true;
Membership.UpdateUser(userInfo);
//Display a message
InformationLabel.Text = "Your account has been " +
"verified and you can now log into the site.";
}
}
}
}
Read On!
Continue onward by reading the next blog post in this series found at the following link: