A critical vulnerability was discovered in React Server Components (Next.js). Our systems remain protected but we advise to update packages to newest version. Learn More

Anders Hattestad
Jan 5, 2011
  5540
(0 votes)

EPiServer pages as users

There are times it can be convenient to have users defined as pages in EPiServer. There are several ways of archiving this. This approaches uses a DDS table with user data and attach to the publish events on the pages.

The code bellow assumes you are using some sort of strong typed pages and those pages you want to be considered users have to implement IAmUser

Code Snippet
  1. public interface IAmAUser
  2. {
  3.      bool EnsureUserData(UserData user);
  4.      bool UpdateUser(MembershipUser user);
  5. }

These 2 methods will be called when a page is published, and when a user is saved thru the membership api.

This code attach to the publish event and checks if the current pages that are being saved have IAmUser and if it is It calls the EnsureUserData method,

Code Snippet
  1. public class attachEvents: PlugInAttribute
  2. {
  3.     public static void Start()
  4.     {
  5.         EPiServer.DataFactory.Instance.PublishedPage += new EPiServer.PageEventHandler(Instance_PublishedPage);
  6.     }
  7.  
  8.     static void Instance_PublishedPage(object sender, EPiServer.PageEventArgs e)
  9.     {
  10.         IAmAUser page=(e.Page as IAmAUser);
  11.         if (page!=null)
  12.         {
  13.             if (!e.PageLink.IsRemote())
  14.             {
  15.                 var user = UserData.GetUserByPageID(e.PageLink.ID);
  16.                 if (user == null)
  17.                     user = new UserData();
  18.                 if (page.EnsureUserData(user))
  19.                 {
  20.                     user.EPiPageID = e.PageLink.ID;
  21.                     UserData.TryToSave(user);
  22.                 }
  23.             }
  24.         }
  25.     }
  26. }

Then its possible to implement the interface on a pagetype. like this. Here is also a great example of how easy it is to add icons with IHavePageIcon.

UserPageType
  1. public class UserPageType : TypedPageData, IHavePageIcon, IAmAUser
  2. {
  3.     #region IAmAUser Members
  4.     public bool EnsureUserData(UserData user)
  5.     {
  6.         user.UserName = UserName;
  7.         user.Email = Email;
  8.         return true;
  9.     }
  10.     public bool UpdateUser(MembershipUser user)
  11.     {
  12.         UserName = user.UserName;
  13.         Email = user.Email;
  14.         return true;
  15.     }
  16.     #endregion
  17.     #region IHavePageIcon Members
  18.     public System.Web.UI.WebControls.Image PageIcon()
  19.     {
  20.         var img = new Image();
  21.         img.ImageUrl = "/images/user.png";
  22.         var users = UserData.GetUserByUserName(UserName);
  23.         if (users != null && users.Length == 1 && users[0].EPiPageID.Equals(this.PageLink.ID))
  24.         {
  25.             //ok
  26.             img.ToolTip = "User has an Unique ID and its " + UserName;
  27.         }
  28.         else
  29.         {
  30.             img.BackColor = System.Drawing.Color.Red;
  31.             img.ToolTip = "";
  32.             foreach (var user in users)
  33.             {
  34.                 img.ToolTip += "User " + user.UserName + " is also defined in epi page " + user.EPiPageID + "\n";
  35.             }
  36.  
  37.         }
  38.         return img;
  39.     }

The actually UserData class looks like this. There is more methods here but you need to download the zip to see those.

UserData
  1. public class UserData : IDynamicData
  2. {
  3.     public UserData()
  4.     {
  5.         CreationDate = DateTime.Now;
  6.     }
  7.     public EPiServer.Data.Identity Id { get; set; }
  8.  
  9.     //Dates
  10.     public virtual DateTime LastActivityDate { get; set; }
  11.     public virtual DateTime CreationDate { get; set; }
  12.     public virtual DateTime LastLockoutDate { get; set; }
  13.     public virtual DateTime LastLoginDate { get; set; }
  14.     public virtual DateTime LastPasswordChangeDate { get; set; }
  15.  
  16.     // Properties
  17.     public virtual string Comment { get; set; }
  18.     public virtual string Email { get; set; }
  19.     public virtual bool IsApproved { get; set; }
  20.     public virtual bool IsLockedOut { get; set; }
  21.     public bool IsOnline { get; set; }
  22.     public virtual string UserName { get; set; }
  23.  
  24.     public string HashedPassword { get; set; }
  25.     public string HashedPasswordSalt { get; set; }
  26.     
  27.     public int EPiPageID { get; set; }

 

I have experienced that if you change the signature of your class (added properties) I have problem with retrieving those new properties from the old data that are already stored. Therefore I usually makes myself a delete all function that removes the whole store for my class., This I do in development of course :)

Then I need to make myself a Membership provider. The important function is the validate user method

Code Snippet
  1. public override bool ValidateUser(string username, string password)
  2. {
  3.     var users = UserData.GetUserByUserName(username);
  4.     if (users.Length == 1)
  5.     {
  6.         var user = users[0];
  7.         if (!string.IsNullOrEmpty(user.HashedPassword))
  8.             if (UserData.CreatePasswordHash(password, user.HashedPasswordSalt).Equals(user.HashedPassword))
  9.                 return true;
  10.  
  11.     }
  12.     return false;
  13. }

On the page that implements IAmUser I’m using a custom property that is username. This property will display if the username is already taken, and will show the pages that are using the same username. This is information that is easy to show in the page tree also as shown in PageIcon method on the UserPageType class above

Code Snippet
  1. [Serializable]
  2. [PageDefinitionTypePlugIn]
  3. public class PropertyUnikUserName:PropertyString
  4. {
  5.     public override IPropertyControl CreatePropertyControl()
  6.     {
  7.         return new PropertyUnikUserNameControl();
  8.     }
  9. }
  10.  
  11. public class PropertyUnikUserNameControl : PropertyStringControl
  12. {
  13.     public override void CreateEditControls()
  14.     {
  15.         base.CreateEditControls();
  16.         var ok = UserData.IsUserOk(ToString());
  17.         if (ok.Ok)
  18.         {
  19.             EditControl.BackColor = System.Drawing.Color.Green;
  20.         }
  21.         else
  22.         {
  23.             EditControl.BackColor = System.Drawing.Color.Red;
  24.             Literal l = new Literal();
  25.             l.ID = this.Name + "Status";
  26.             l.Text = "<div>"+ok.OkMessage.Replace("\n", "<br />")+"</div>";
  27.             this.Controls.Add(l);
  28.         }
  29.     }
  30. }

What we have now is a membership provider that are based on pages in EPiServer. We don’t have a role provider for these users, but as shown in my blog post about multiplexing providers that is not necessarily. Since we can use the normal one.

Download zip file here

Jan 05, 2011

Comments

Please login to comment.
Latest blogs
A day in the life of an Optimizely OMVP: Learning Optimizely Just Got Easier: Introducing the Optimizely Learning Centre

On the back of my last post about the Opti Graph Learning Centre, I am now happy to announce a revamped interactive learning platform that makes...

Graham Carr | Jan 31, 2026

Scheduled job for deleting content types and all related content

In my previous blog post which was about getting an overview of your sites content https://world.optimizely.com/blogs/Per-Nergard/Dates/2026/1/sche...

Per Nergård (MVP) | Jan 30, 2026

Working With Applications in Optimizely CMS 13

💡 Note:  The following content has been written based on Optimizely CMS 13 Preview 2 and may not accurately reflect the final release version. As...

Mark Stott | Jan 30, 2026

Experimentation at Speed Using Optimizely Opal and Web Experimentation

If you are working in experimentation, you will know that speed matters. The quicker you can go from idea to implementation, the faster you can...

Minesh Shah (Netcel) | Jan 30, 2026