Membership customizations

   —   
This article provides some examples of how you can customize the membership module to better fit your needs.
 Hi there,

We are sometimes asked about the membership functionality which covers the assignment of the user to sites and the behavior of this assignment.

How the system currently works

Basically, what our solution offers is a shared account storage for all web sites within single database. This is very useful when you web is distributed in multiple domains with completely different content. A great example of this is our own web.
  • There is a main domain www.kentico.com which contains our main, company web site.
  • Then, there is this devnet.kentico.com web site which is mainly for the devepopers and is completely different than the main web site.
  • In the future, there will be a new partner portal web site, which again will be different, for specific users (partners).
What really matters is that when you register on one web site, you automatically have the account on all the other web sites. That is the power of shared account storage. The site visitors always register for all the sites. You can see in the admin interface that there are checkboxes in the user details (when accessed from Site manager) where you can set to which sites the user is assigned. The important thing is that this settings do not apply for live site.

Yes, that is right, it is not a bug, this is done by design.

On the other hand, looking at the content editors, other group of people is responsible for each web site, e.g. main site has only specific admin because it is pretty static, DevNet is only managed by the people who have something to say to the developers (our Support and Developers), and the Partner web site would be managed by the Partner manager guy.

That's where the assignment of user to site applies. It actually checks if the user can access the admin interface of the web site.

It is important to say that this behavior is currently the only one possible out of the box. We haven't expected that anyone will need anything else (by that I mean some number of customers that would really really need it). Almost all the customers which gave us some feedback wanted this behavior as the default and only one and it also matched our needs.

Since there is a very slowly growing number of customers (so far I know about 3 of you at the moment, maybe, there is more) which would like to allow specific site visitors only to log in on specific site, we decided to provide you with some guidance how you can achieve this by customizing our code. 

All the thanks belong to our membership team guys which provided me with these useful  and nice examples, I will sure let them know if you post your thanks to the comments ;-)

How to customize the registration form to assign the user to specific sites

This is quite simple change, to make it by the book of Kentico code (in other words the recommended way), please perform the following steps:

1) Go to the SiteManager -> Webparts -> Membership -> Registration form, the Properties tab, and add the property AssignToSites, which would be text, with some length that you think would be enough, e.g. 500 with textbox field.



2) Open the web part code-behind file ~/CMSWebParts/Membership/registrationform.ascx.cs and implement a new property which will reflect the new property of the web part.

NOTE: If you want to ensure that the wep part won't be overwritten by the upgrade process to new version, please clone the web part and modify the cloned one.

/// <summary>
/// Gets or sets the sites where is user assigned after successful registration
/// </summary>
public string AssignToSites
{
  get
  {
    return ValidationHelper.GetString(this.GetValue("AssignToSites"), "");
  }
  set
  {
    this.SetValue("AssignToSites", value);
  }
}


3) Modify the code of the btnOK_Click event, replace the existing code

if (CMSContext.CurrentSite != null)
{
  string siteName = CMSContext.CurrentSiteName;
  // Add new user to the current site
  UserInfoProvider.AddUserToSite(ui.UserName, siteName);


with new one

string[] siteList = this.AssignToSites.Split(';');
foreach (string siteName in siteList)
{
  // Add new user to the site
  UserInfoProvider.AddUserToSite(ui.UserName, siteName);


4) Set-up the web part property in the design mode to the list of web site code names separated by semicolon, e.g. "CorporateSite;YourSite"

How to customize the Logon form to allow login only for the users who are assigned to the site

This own is just a little longer code, but consists only of the code modification, just add following code to the codebehind file ~/CMSWebparts/Membership/logonform.aspx.cs to the method Login1_LoggingIn, just after the Banned IP check.

// Restrict only to users assigned to current site
if (CMSContext.CurrentSite != null) 
{
  // Try to find user with specified username
  UserInfo ui = UserInfoProvider.GetUserInfo(Login1.UserName);

  // Check if user is assigned to current site
  if ((ui != null) && (!ui.IsInSite(CMSContext.CurrentSiteName)))
  {
    // Cancel logging
    e.Cancel = true;

    // Write failure text
    LocalizedLiteral failureLit = Login1.FindControl("FailureText") as LocalizedLiteral;
    if (failureLit != null)
    {
      failureLit.Visible = true;
      failureLit.Text = DataHelper.GetNotEmpty(this.FailureText, ResHelper.GetString("login_failuretext"));
    }
  }
}


It is approximately the line number 457. Of course it depends on the webpart(s) you are using for logging in, you may modify more of them the similar way.

So this is basically how you enable the other than default behavior, that is expected by some customers.

At this point, if this is enough for you, you don't need to read further. However, if you are interested and if you use the Social networking edition, the following examples may also be very useful for you.

How to modify the registration form to assign the user to specific community groups

This is very similar to the first example, just different in the name of the property and code:

1) Go to the SiteManager -> Webparts -> Membership -> Registration form, the Properties tab, and add the property AssignToGroups, which would be text, with some length that you think would be enough, e.g. 500 with textbox field.

2) Open the web part code-behind file ~/CMSWebParts/Membership/registrationform.ascx.cs and implement a new property which will reflect the new property of the web part.

/// <summary>
/// Gets or sets the groups where is user assigned after successful registration
/// </summary>
public string AssignToGroups
{
  get
  {
    return ValidationHelper.GetString(this.GetValue("AssignToGroups"), "");
  }
  set
  {
    this.SetValue("AssignToGroups", value);
  }
}


3) Add following code to the btnOK_Click method of the webpart, to the same place where was the code for assignment to the sites above:

Add using:

using CMS.Community;

Add code:

string[] groupList = this.AssignToGroups.Split(';');

if (CMSContext.CurrentSite != null)
{
  string siteName = CMSContext.CurrentSiteName;

  // Go trough all groups
  foreach (string groupName in groupList)
  {
    // Retrieve group
    GroupInfo gi = GroupInfoProvider.GetGroupInfo(groupName, siteName);

    if (gi != null)
    {
      // Create GroupMemberInfo
      GroupMemberInfo gmi = new GroupMemberInfo();

      // Assign membership values
      gmi.MemberJoined = DateTime.Now;
      gmi.MemberRejectedWhen = DateTimeHelper.ZERO_TIME;
      gmi.MemberGroupID = gi.GroupID;
      gmi.MemberUserID = ui.UserID;
      gmi.MemberStatus = GroupMemberStatus.Approved;
      gmi.MemberApprovedWhen = DateTime.Now;

      // Store to DB
      GroupMemberInfoProvider.SetGroupMemberInfo(gmi);
    }
  }
}


And that's it. As you can see in the code, the group membership of the user is automatically approved, you can modify it by your needs. You now just set the property to the list of the group code names separated by semicolon.

How to customize the logon form to allow login only for the members of specific Group(s)

Again, this is very similar to the second example where we checked the site assigment:

1) Just add the following code to the same place of ~/CMSWebparts/Membership/logonform.aspx.cs to the method Login1_LoggingIn you added the code for the site check:

Add using:

using CMS.Community;

Add code:

// If allowed group is set
if (!String.IsNullOrEmpty(this.AllowedGroup))
{
  // Try to retrieve userinfo and groupinfo
  UserInfo ui = UserInfoProvider.GetUserInfo(Login1.UserName);
  GroupInfo gi = GroupInfoProvider.GetGroupInfo(this.AllowedGroup, CMSContext.CurrentSiteName);

  if ((ui != null) && (gi != null))
  {
    // Check if user is member of the group
    if (!GroupMemberInfoProvider.IsMemberOfGroup(ui.UserID, gi.GroupID))
    {
      // Cancel logging
      e.Cancel = true;

      // Write failure text
      LocalizedLiteral failureLit = Login1.FindControl("FailureText") as LocalizedLiteral;
      if (failureLit != null)
      {
        failureLit.Visible = true;
        failureLit.Text = DataHelper.GetNotEmpty(this.FailureText, ResHelper.GetString("login_failuretext"));
      }
    }
  }
}


And that's it. Now you just set-up the web part property to the list of the group code names separated by semicolon. And again, you need to do this in every logon web part where you want to enable this.

Here are the sample codes: Membership.zip

That is all for now, I hope this helped you at least a little bit, and as always, get ready for my next post.
Share this article on   LinkedIn Google+

Martin Hejtmanek

Hi, I am the CTO of Kentico and I will be constantly providing you the information about current development process and other interesting technical things you might want to know about Kentico.

Comments

Martin Hejtmanek commented on

Hi Katy,

You can do it with the custom security handler, see this documentation chapter:

http://devnet.kentico.com/docs/devguide/security_handler.htm

For further details, please contact our support at support@kentico.com

Katy commented on

Hi,

I want to intercept the log in functionality to do some additional checking if custom fields are set for that user. How can I do this? I'm using Version 3.1a

Thanks,
Katy

Martin Hejtmanek commented on

Hi,

You have several options. You can either make that template specific for each site (Save it as a new one for another site), or you can create ad-hoc template for that specific document. Or you can use reusable templates and the new Widgets functionality for editors in the new 5.0 version. All of these will do exactly what you need. See the latest Blog posts on DevNet on new features of v5.0 or the documentation for details.

Binary commented on

recently(exactly today) I contacted your support about issue
it really helps

but I have another issue which is that I need also the Page Templates to be separated per site

as
if you have a Site A Designer and Site B Designer

any Designer will add a web Part to "Page Template A" which is used in Both "Site A" and "Site B" , that web Part will appear in Both Sites

any change that will be made by any Desginer will affect the other work, which is I don't need

Martin Hejtmanek commented on

Hi Darren,

I don't have the exact code sample, but it should be very similar, my guess is that if you add following code right before the "// Set current user" comment of the ProcessStep method, that should do the work. (I dit not exactly test it so they may be some syntax issues)

// Check if user is assigned to current site
if ((ui != null) && (!ui.IsInSite(CMSContext.CurrentSiteName)))
{
// Display the error message
lblError.Text = ResHelper.GetString("ShoppingCartCheckRegistration.LoginFailed");
lblError.Visible = true;
return false;
}

You just check the user-site settings the same way like in the examples above. The concept is the same.

Darren commented on

Hi Martin,

Do you have the code needed to add into the ShoppingCartCheckRegistration.ascx.cs file to make it single-site?

Cheers

Martin Hejtmanek commented on

Hi Darren,

I forgot to mention that ... if there is some spare time, we will include this into the next version (no promise). And yes, you need to implement that in every registration form you are using on your site, including the shopping cart one.

darren wainwright commented on

Will the above also need doing to the shopping cart registration form??

Darren Wainwright commented on

Wow - Glad i read this!! i assumed that when a visitor registered to a site he would have only access to that one site.

Off to implement now :-)

Would be great if, in future releases, there were an option in the system settings to set either way.