Approving Users and Assigning them to Roles After They Sign Up for an Account

Back in July I wrote an article that showed how you can require your users to confirm their e-mail addresses before they can access your site after signing up for a new account. In this article I describe a similar but slightly different technique where an administrator of the site can approve the account before the user gains access to the site.

Approving Users

If you haven't read the original article yet, you're encouraged to do it now as it explains the core principle of approving user accounts. In this article, I'll only describe the variations needed to let an administrator approve the account.

From a high-level perspective, here's what you need to do to let an administrator of your site approve the account of a newly signed up user:

  1. Let the user sign up for an account
  2. Intercept the sending of the e-mail and either change the existing e-mail so it's send to the administrator of the site, or create an additional e-mail message instead. Add a link to the mail message body that lets an administrator approve the account.
  3. Create a page that lets an administrator approve the account, and optionally assign it to one or more roles.

You'll see how to accomplish these steps next.

1. Let the user sign up for an account

This is similar to the implementation in the original article: add a CreateUserWizard to a page (called SignUp.aspx in the demo site), and set DisableCreatedUser to True so the user account isn't activated automatically when it gets created. Then write code for the SendingMail event and redirect the e-mail to an administrator instead of to the user that signed up for the account. Here's the code for the CreateUserWizard (note: you find a fully working example in the download for this article):

<asp:CreateUserWizard ID="CreateUserWizard1" runat="server" DisableCreatedUser="True" 
     OnCreatedUser="CreateUserWizard1_CreatedUser" OnSendingMail="CreateUserWizard1_SendingMail" 
     CompleteSuccessText="Your account has been successfully created. 
      You won't be able to log in until your account has been approved by an administrator.">
  <MailDefinition BodyFileName="~/App_Data/NewAccount.txt" From="imar@example.com" 
       Subject="A new account has been created">
  </MailDefinition>
  <WizardSteps>
    <asp:CreateUserWizardStep runat="server" />
    <asp:CompleteWizardStep runat="server" />
  </WizardSteps>
</asp:CreateUserWizard>

2. Intercept the sending of the e-mail

In the code behind of SignUp.aspx, you can modify the e-mail message that is normally send to the user, and send it to an administrator instead, like this:

protected void CreateUserWizard1_SendingMail(object sender, MailMessageEventArgs e)
{
  // Remove the original recipient
  e.Message.To.Clear();
  // Add the Administrator account as the new recipient
  e.Message.To.Add("administrator@example.com");
  string confirmLink = string.Format("{0}://{1}/Confirm.aspx?ConfirmationKey={2}&UserName={3}",
         Request.Url.Scheme, Request.Url.Authority, _accountConfirmationKey, 
         CreateUserWizard1.UserName);
  e.Message.Body = e.Message.Body.Replace("##ConfirmLink##", confirmLink);
}

First, this code clears the To collection by calling Clear. This removes the original recipient so the user that signed up for an account doesn't receive a copy of the message. Then the e-mail address of the Administrator is added by calling Add on the To collection and passing in the administrator's e-mail address. The remainder of the code is identical to the code presented in the previous article. Also, the code in the CreatedUser event to generate a random confirmation key for the user is exactly the same. To see how this code looks, check out the original article or download the source at the end of this article.

3. Create a page that lets an administrator approve the account and assign it to roles

The demo that comes with this article does not only let an administrator approve the account; it also lets the administrator assign the new user to zero or more roles. To implement this, I did the following:

  • Enable Roles in web.config:
    <roleManager defaultProvider="DefaultRoleProvider" enabled="true">
  • In Global.asax, make sure the roles are created automatically when they don't exist:
    void Application_Start(object sender, EventArgs e) 
    {
      if (!Roles.RoleExists("Administrators"))
      {
        Roles.CreateRole("Administrators");
      }
      if (!Roles.RoleExists("Members"))
      {
        Roles.CreateRole("Members");
      }
    }      

    This is optional and you can leave out this step if you're sure the required roles already exists in your database.

  • Display the roles when the Confirm.aspx page is loaded. For this, I added a CheckBoxList to the page that looks like this:

    <asp:CheckBoxList ID="RolesList" runat="server" />
    And in Code Behind I assign the list of available roles using the static GetAllRoles method of the Roles class that comes with ASP.NET:

    protected void Page_Load(object sender, EventArgs e)
    {
      if (!Page.IsPostBack)
      {
        RolesList.DataSource = Roles.GetAllRoles();
        RolesList.DataBind();
      }
      _userName = Request.QueryString.Get("UserName");
      _accountKey = Request.QueryString.Get("ConfirmationKey");
    }
  • When the account is approved (with code identical to the code presented in the original article), I assign the account to the roles that the administrator selected like this:
    protected void SaveChanges_Click(object sender, EventArgs e)
    {
      var profile = ProfileCommon.Create(_userName) as ProfileCommon;
      if (_accountKey == profile.AccountConfirmationKey)
      {
        var user = Membership.GetUser(_userName);
        user.IsApproved = true;
        Membership.UpdateUser(user);
        foreach (ListItem role in RolesList.Items)
        {
          if (role.Selected)
          {
            Roles.AddUserToRole(_userName, role.Value);
          }
        }
        Status.Text = "Account confirmed successfully.";
      }
      else
      {
        Status.Text = "Something went wrong while confirming your account.";
      }
    }      
    This code simply loops through all the available items of the RolesList control. When the Selected property is true, the administrator checked that role and the user is added to it by calling Roles.AddUserToRole.

Once this code has run, the new account is active, and has been assigned to the roles the administrator has selected for that account.

Extending the Sample

This is just a short demo to show the underlying principles. If you want to use this in a real-world website, you're advised to make the following changes:

  • Block the Confirm.aspx using URL authorization so only administrators can access it. Currently the file can be requested by all users.
  • Consider if you still want to send the user that signed up for an account an e-mail or not. In that case, you need to create a new MailMessage using the classes in the System.Net.Mail namespace to send a separate e-mail to the administrator from the SendingMail event.
  • Centralize the e-mail addresses in the web.config. Storing e-mail addresses in pages directly as is done with SignUp.aspx makes your site harder to maintain.

Downloads

The full source code for this application (C# only)


Where to Next?

Wonder where to go next? You can post a comment on this article.

Doc ID 572
Full URL https://imar.spaanjaars.com/572/approving-users-and-assigning-them-to-roles-after-they-sign-up-for-an-account
Short cut https://imar.spaanjaars.com/572/
Written by Imar Spaanjaars
Date Posted 11/11/2012 15:38

Comments

Talk Back! Comment on Imar.Spaanjaars.Com

I am interested in what you have to say about this article. Feel free to post any comments, remarks or questions you may have about this article. The Talk Back feature is not meant for technical questions that are not directly related to this article. So, a post like "Hey, can you tell me how I can upload files to a MySQL database in PHP?" is likely to be removed. Also spam and unrealistic job offers will be deleted immediately.

When you post a comment, you have to provide your name and the comment. Your e-mail address is optional and you only need to provide it if you want me to contact you. It will not be displayed along with your comment. I got sick and tired of the comment spam I was receiving, so I have protected this page with a simple calculation exercise. This means that if you want to leave a comment, you'll need to complete the calculation before you hit the Post Comment button.

If you want to object to a comment made by another visitor, be sure to contact me and I'll look into it ASAP. Don't forget to mention the page link, or the Doc ID of the document.

(Plain text only; no HTML or code that looks like HTML or XML. In other words, don't use < and >. Also no links allowed.