Mugshot

Hey I'm Lee. My blog was put up to house useful nuggets I could refer back to, document my learning curves on new technologies and house tutorials I write for Umbraco and other .NET stuff.

All thoughts and comments on here are my own, and in no way reflect my employer - I also take no responsibility for spelling, grammar or terminology, so read at your own risk!

Blogs I Read

Sites I Like

Umbraco Membership Templates

Creating a private/membership area in your Umbraco site really is a piece of cake - If you don't know how to restrict public access to a node (And its children) then I suggest you have a quick look through the ' Umbraco Editors Guide' for more in depth information.

But in short, to create a private membership area you firstly need to make sure you have a 'member group' setup in members section (For the templates below I have created a membergroup in Umbraco called 'SiteMembers') - And then just browse to the section/nodes in your site you want to restrict access to and right click and choose public access > Role Based Protection and assign the SiteMembers role to have access.

role

role2

Templates

Once you have this done, you need to have a few things to make it work - To help speed this along I have made some templates which you can use below.  Each of the below is a usercontrol and added as a macro in the website, and once added will give you full register, login and forgotten password functionality. Its all been setup to use the JQuery validate too, so you need to make sure you have that in your main template ready if you want to use it.

**IMPORTANT**: These are just stripped out templates to get you going, you NEED to add your own security logic to check the users input for things like XSS attacks etc…

Register Template

This has macro parameters which you'll need to add to the macro, its just for redirecting to the member to a page after successful registration

ASCX

<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="Register.ascx.cs" Inherits="Register" %>

<div id="registersubscriberform">

    <p>All items marked with a * are mandatory</p>
    <asp:Literal ID="litError" runat="server" />
    <div class="formholder">
        <div class="formrow">
            <div class="formleft"><label for="<%= tbUsername.ClientID %>">Username*</label></div>
            <div class="formright">
                <asp:TextBox ToolTip="Enter username" CssClass="required" ID="tbUsername" runat="server" ClientIDMode="Static" />
            </div>
        </div>

        <div class="formrow">
            <div class="formleft"><label for="<%= tbEmail.ClientID %>">Email*</label></div>
            <div class="formright">
                <asp:TextBox ToolTip="Enter email" CssClass="required email" ID="tbEmail" runat="server" ClientIDMode="Static" />
            </div>
        </div>

        <div class="formrow">
            <div class="formleft"><label for="<%= tbPassword.ClientID %>">Password*</label></div>
            <div class="formright">
                <asp:TextBox ToolTip="Enter a password" CssClass="required" ID="tbPassword" TextMode="Password" runat="server" ClientIDMode="Static" />
            </div>
        </div>

        <div class="formrow">
            <div class="formleft"></div>
            <div class="formright">
                <asp:Button ID="btnRegister" runat="server" Text="Register" OnClick="RegisterPlayer" />
            </div>
        </div>
    </div>

</div>

CodeBehind

using System;
using System.Web.Security;
using System.Web.UI;
using umbraco;
using umbraco.BusinessLogic;
using umbraco.cms.businesslogic.member;

    public partial class Register : UserControl
    {
        // Macro Parameters
        public int SuccessfulLoginPage { get; set; }

        // Member Type & Group
        private const string MembersType = "SiteMembers";
        private const string MembersGroup = "SiteMembers";

        // Error format
        private const string ErrorFormat = "<p class=\"formerror\">{0}</p>";

        protected void RegisterPlayer(object sender, EventArgs e)
        {
            // Do some server side checks just to be on the safe side
            if (string.IsNullOrWhiteSpace(tbEmail.Text) | string.IsNullOrWhiteSpace(tbPassword.Text) | string.IsNullOrWhiteSpace(tbUsername.Text))
            {
                litError.Text = string.Format(ErrorFormat, "Please complete all fields");
                return;
            }                

            // Check the user isn't already registered
            if (Member.GetMemberFromEmail(tbEmail.Text) == null && Member.GetMemberFromLoginName(tbUsername.Text) == null)
            {
                // Set the member type and group
                var mt = MemberType.GetByAlias(MembersType);
                var addToMemberGroup = MemberGroup.GetByName(MembersGroup);

                //create the member, and set the password and email
                var m = Member.MakeNew(tbUsername.Text, mt, new User(0));
                m.Password = tbPassword.Text;
                m.Email = tbEmail.Text;

                // Add the member to the group
                m.AddGroup(addToMemberGroup.Id);

                //Save member
                m.Save();

                //Generate member Xml Cache
                m.XmlGenerate(new System.Xml.XmlDocument());

                // NOTE: This Is Optional
                // Login the user
                FormsAuthentication.SetAuthCookie(tbUsername.Text, false);

                // Redirect to successful page (Usually their profile or member page)
                Response.Redirect(library.NiceUrl(SuccessfulLoginPage));
            }
            else
            {
                // Error, member already exists with email or username used
                litError.Text = string.Format(ErrorFormat, "User already exists");
            }
        }
    }

Login Template

Again this has macro parameters which you'll need to add to the macro, its just for redirecting to the member to a page after successful login

ASCX

<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="Login.ascx.cs" Inherits="Login" %>

<asp:Literal ID="litError" runat="server" />
<asp:Login RenderOuterTable="false" ID="ctlLogin" runat="server" OnLoginError="OnLoginError" onloggedin="OnLoggedIn" RememberMeSet="True" VisibleWhenLoggedIn="False">
    <LayoutTemplate>
        <div id="login">           
             
            <div class="formholder">

            <div class="formrow">
                <div class="formleft"><label>Username</label></div>
                <div class="formright">
                    <asp:TextBox ID="UserName" CssClass="textbox required" ToolTip="Enter username" runat="server"></asp:TextBox>
                </div>
            </div>

            <div class="formrow">
                <div class="formleft"><label>Password</label></div>
                <div class="formright">
                    <asp:TextBox ID="Password" CssClass="textbox required" ToolTip="Enter password" runat="server" TextMode="Password" />
                </div>
            </div>           

            <div class="formrow">
                <div class="formleft">&nbsp;</div>
                <div class="formright">
                    <asp:CheckBox ID="RememberMe" runat="server" Text="Keep me logged in" />
                </div>
            </div>
            
            <div class="formrow">
                <div class="formleft">&nbsp;</div>
                <div class="formright">
                    <asp:Button ID="LoginButton" CssClass="loginButton" runat="server" CommandName="Login" Text="Login" /> />
                </div>
            </div>

            </div>

        </div>

    </LayoutTemplate>
</asp:Login>

CodeBehind

using System;
using System.Web.UI;
using umbraco;
using umbraco.cms.businesslogic.member;

    public partial class Login : UserControl
    {
        // Macro Parameters
        public int SuccessfulLoginPage { get; set; }

        // Error format
        private const string ErrorFormat = "<p class=\"formerror\">{0}</p>";

        // If there is an error logging in, this method will fire and put the error in the error lit
        protected void OnLoginError(object sender, EventArgs e)
        {
            litError.Text = string.Format(ErrorFormat, ctlLogin.FailureText);
        }

        // This fires once the user has successfuly logged in
        protected void OnLoggedIn(object sender, EventArgs e)
        {
            // ** OPTIONAL! **
            // You can do some custom logic here to check if user is banned or something similar
            // Get the user
            var m = Member.GetMemberFromLoginName(ctlLogin.UserName);
            // ** OPTIONAL! **

            // Send the user to the correct authenticated page, once successfully logged in
            Response.Redirect(library.NiceUrl(SuccessfulLoginPage));
        }
    }

Forgotten Password Template

The from email is stored as a constant in the code behind, change this as you need - Usually this is a site wide setting I have on the home node.

NOTE: To use this, you need to make sure that 'enablePasswordReset' in your web.config is set to 'true'

ASCX

<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="ForgotPassword.ascx.cs" Inherits="ForgotPassword" %>

<p>Enter your email address</p>
<asp:Literal ID="litError" runat="server" />
<p><asp:TextBox ID="tbEmail" runat="server"></asp:TextBox> 
<asp:Button ID="btnSubmit" runat="server" Text="Send Password" onclick="BtnSubmitClick" /></p>

CodeBehind

using System;
using System.Text;
using System.Text.RegularExpressions;
using System.Web.Security;
using System.Web.UI;
using umbraco;
using umbraco.cms.businesslogic.member;

public partial class ForgotPassword : UserControl
{
    // Error format
    private const string ErrorFormat = "<p class=\"formerror\">{0}</p>";

    // From Email Address
    private const string FromEmail = "noreply@mywebsite.com";

    protected void BtnSubmitClick(object sender, EventArgs e)
    {
        // Try and get the member from the email address entered
        var cMember = Member.GetMemberFromEmail(tbEmail.Text);

        // Check we have a member with that email address
        if (cMember != null)
        {
            // Found the user
            // Generate a password which we'll email the member
            var password = Membership.GeneratePassword(10, 1);
            password = Regex.Replace(password, @"[^a-zA-Z0-9]", m => "9");

            // Change the password to the new generated one above
            var member = Membership.GetUser(cMember.LoginName);
            member.ChangePassword(member.ResetPassword(), password);

            // Save the password/member
            cMember.Save();

            // update the XML cache 
            cMember.XmlGenerate(new System.Xml.XmlDocument());

            // Now email the member their password
            var sb = new StringBuilder();
            sb.AppendFormat(string.Format("<p>Please find your new password below to access the site</p>"));
            sb.AppendFormat("<p><b>{0}</b></p>", password);
            library.SendMail(FromEmail, cMember.Email, "Password Reset", sb.ToString(), true);

            // Disable the button to stop them pressing it again
            btnSubmit.Enabled = false;

            // Show a message to the user
            litError.Text = string.Format(ErrorFormat, "Password Sent");
        }
        else
        {
            // Can't find a user with that email
            litError.Text = string.Format(ErrorFormat, "Can't find a user with that email address");
        }
    }
}

Styles

A few styles just to make it look nice from the start - You don't have to use these obviously.

.formholder { overflow:hidden; width:800px;}
.formrow { padding:5px 0; clear:both; float:left; width:100%; clear:both; }
.formleft { float:left; width:30%; margin:0; line-height:20px; font-size:1.4em; padding:8px 0 0 0; }
.formright { float:right; width:59%; }
.formrow input[type=text], .formrow input[type=password] { padding:6px; width:250px; }
.formrow input[type=submit], .formrow input[type=button] { padding:3px 7px; cursor:pointer; }
.formrow select { padding:6px; width:255px; }
.formrow label.error { margin:0 0 0 10px;}
p.formerror { font-weight: bold;color: red;}
Back to top