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.


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"> </div>
<div class="formright">
<asp:CheckBox ID="RememberMe" runat="server" Text="Keep me logged in" />
</div>
</div>
<div class="formrow">
<div class="formleft"> </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;}