Custom member sections?

Hey evenryone.

I have a question for you all, we have two websites that share an Umbraco installation.

The first site uses members and now the second site wants to use members as well.

Now I am wondering how to handle this in the backoffice, the two websites should not be able to see eachothers members, is it posiblity (viable) to make custom member sections, one for website a and one for website b?

Do you have any experience here?

Hi @mdp-jf

You can create different member types, so website A could use a different member type to website B, that way you can use code to check that you are looking at the correct member type based on the website. The other issue though is that you can only have one member in the CMS with the same username/email so they wouldn’t be able to register separately under each website… Not sure whether that helps or not?

Justin

Oh thats right, didnt even think about the problem if the same person need a member on each site.

But even if we do it like that, Website A would still be able to see Website B’s members in the member section?

Not if you check the member type on login to ensure website A can only see the member type for website A and website B can only see it’s member types. Effectively using member types as a way of identifying which website they belong to. Alternatively, you could just create a custom property on a member to identify which site they belong too.

Sorry for asking, but how can we do that?

Something like this should work (untested though so needs checking):

using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Core.Cache;
using Umbraco.Cms.Core.Logging;
using Umbraco.Cms.Core.Routing;
using Umbraco.Cms.Core.Security;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Web;
using Umbraco.Cms.Infrastructure.Persistence;
using Umbraco.Cms.Web.Common.Controllers;
using Umbraco.Cms.Web.Common.Filters;
using Umbraco.Cms.Web.Common.Models;
using Umbraco.Cms.Web.Website.Controllers;

public class CustomLoginController : SurfaceController
{
    private readonly IMemberManager _memberManager;
    private readonly IMemberSignInManager _signInManager;

    public CustomLoginController(
        IUmbracoContextAccessor umbracoContextAccessor,
        IUmbracoDatabaseFactory databaseFactory,
        ServiceContext services,
        AppCaches appCaches,
        IProfilingLogger profilingLogger,
        IPublishedUrlProvider publishedUrlProvider,
        IMemberManager memberManager,
        IMemberSignInManager signInManager)
        : base(umbracoContextAccessor, databaseFactory, services, appCaches, profilingLogger, publishedUrlProvider)
    {
        _memberManager = memberManager;
        _signInManager = signInManager;
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    [ValidateUmbracoFormRouteString]
    public async Task<IActionResult> HandleLogin([Bind(Prefix = "loginModel")] LoginModel model)
    {
        if (!ModelState.IsValid)
            return CurrentUmbracoPage();

        // Look up the member first so we can inspect type before signing in
        var member = await _memberManager.FindByNameAsync(model.Username)
                     ?? await _memberManager.FindByEmailAsync(model.Username);

        if (member is null)
        {
            ModelState.AddModelError("loginModel", "Invalid username or password");
            return CurrentUmbracoPage();
        }

        // The bit you asked about
        if (!string.Equals(member.MemberTypeAlias, "customerMember", StringComparison.OrdinalIgnoreCase))
        {
            ModelState.AddModelError("loginModel", "This account type cannot log in here.");
            return CurrentUmbracoPage();
        }

        var result = await _signInManager.PasswordSignInAsync(
            model.Username, model.Password, model.RememberMe, lockoutOnFailure: true);

        if (!result.Succeeded)
        {
            ModelState.AddModelError("loginModel", "Invalid username or password");
            return CurrentUmbracoPage();
        }

        return RedirectToCurrentUmbracoPage();
    }
}

But this is for the frontend isnt it?

I am talking about in the backoffice, or perhaps I am misunderstanding your code :sweat_smile:

That example shows you how to check when a member logs in. What is it you need to know? How to create another member type or add a new property to a member?

Sorry, I think I wasn’t clear enough — let me try again.

I’m not talking about members logging in on the frontend. I’m talking about backoffice users (the people editing content in Umbraco).

Scenario:

  • “Alice” is a backoffice user who administers Website A

  • “Bob” is a backoffice user who administers Website B

  • Both websites have members, stored in the same Umbraco installation

  • When Alice opens the Members section in backoffice, she can see all members, including Website B’s

  • Same for Bob — he can see Website A’s members

I want Alice to only see/edit Website A’s members, and Bob to only see/edit Website B’s. Member Types / a custom property would let me filter in code, but the built-in Members section in backoffice still lists everything.

Ah sorry for the confusion - yes, that code was for the frontend login, stopping members from site A logging in via site B’s login page. Different problem to what you’re asking about.

For the backoffice, unfortunately Umbraco doesn’t have built-in filtering of the Members section based on user groups/types - it’ll always show a flat list of every member regardless of type.

The cleanest approach is to build a custom backoffice section (e.g. “Site A Members” and “Site B Members”), each with its own tree / collection view that queries members filtered by member type (or a custom property on the member). You’d then set up user groups so Site A editors only have access to the Site A Members section, and remove their access to the default Members section entirely (same for Site B). That would obviously be a lot of backoffice development and re-writing out of the box Umbraco member UI which may not be ideal.

The only other alternative would be to deploy both sites as separate instances.

Alright, thank you very much for helping out :slight_smile: