1

How can I restrict content frontend to specific user groups? There seems no sensible way to do this out of the box. For example group permissions in CP are all about CP - there is no view option.

Never had a use case for this before today but have one now and finding Craft3 coming up short :(

Scenario is a support portal where different companies can provide user specific content. Idea is login with company id (done that ok via a plugin) but then once logged in they get redirected to content for that specific company.

So I have two probs now: redirect to company 'home page', and restrict access to content. I've considered splitting content into sites and pairing users with sites. I've considered section root parent and checking permissions for top of tree in twig. I'm thinking restricting per section is best and adding company homepage as entry field in user field or user group field and managing access via plugin + twig but its all feeling very heavy handed....

3
  • 1
    Have you tried the answers to this question "Check user is in User Group / Custom User Permissions?" craftcms.stackexchange.com/questions/1087/…
    – Alex Roper
    Feb 4, 2020 at 21:00
  • Thanks Alex - hadn't seen it looks useful. But cant believe there is no front end permission view and having to roll a plugin for what should be core is annoying++
    – joomkit
    Feb 5, 2020 at 11:41
  • Also, it might be helpful to talk thru the problem on the Craft CMS Discord channel: craftcms.com/discord
    – Alex Roper
    Feb 5, 2020 at 18:51

3 Answers 3

4

If you setup a User Group with the same handle as the Site you want them to have access to, this could be fairly easy.

Let's say you have a site called "Acme" setup in the Sites settings. You also created a corresponding User Group called "Acme." The handles for the Acme Site and Acme User Group are both "acme."

When you're on the Acme site's front-end, possibly example.com/acme depending on how you set up your site URLs, the {{ currentSite.handle }} tag will return acme.

To test if a user has access to content in your template you can use something like {% if currentUser.isInGroup(currentSite.handle) %}.

Adding this to any template will prevent unauthorized access if a user is not in a group:

{% if not currentUser.isInGroup(currentSite.handle) %}  
  {% exit 403 %}
{% endif %}

You would also probably want to allow admins or users groups who can access the control panel:

allow admins:

{% if not currentUser.isInGroup(currentSite.handle) or not currentUser.admin %}  
  {% exit 403 %}
{% endif %}

... or allow any user that can access the control panel:

{% if not currentUser.isInGroup(currentSite.handle) or not currentUser.can('accessCp') %}  
  {% exit 403 %}
{% endif %}

Redirecting to the correct site after a login page is a little trickier because users can belong to more than one group.

But assuming that users only belong to one group you could redirect users to a sort of "routing" template that's only job is to send you to the right place.

{% set firstGroup = currentUser.getGroups()[0] ?? null %}

{% if firstGroup %}
  {% redirect firstGroup.handle %}
{% else %}
  ... default redirect or error 
{% endif %}

Also, here's a list of permission you can use with the currentUser.can() method:

https://docs.craftcms.com/v3/users.html#permissions

1
  • Thanks Alex. Your reply is a good reminder to spell out the scenario, and is a most welcome creative addition/solution to the problem.I need to support other languages within a company but i think i can see how this will work. I'm going to implement the above and jump on discord if I find problems. Thanks again
    – joomkit
    Feb 6, 2020 at 14:48
1

I've done this! Let me try to explain without writing a small novel. There were a lot of bits, but it works.

Start by creating a user group for every client. As you create these, write down the group handle. (Note: doesn't need any permissions other than logging in.)

Make a channel containing your clients as individual entries, and in the fields for each entry, add a text field called "Client Portal Handle" - and copy the handle from the user groups to that field.

Then, in my the templates, I'm setting up the page urls to be /portal// - and I set a field (I called it 'associatedClient') on entry, so each entry goes to that client.

And, here's the bit that makes it all work, in a template, it's got code that says:

{% set client = entry.associatedClient.one() %}
{% set cg = client.portalGroup %}

{% if currentUser.admin or currentUser.isInGroup(cg) %}
  {# document template goes here #}
{% else %}
  {# back to the login page #}
{% endif %}

Line 1 gets the client attached to the doc. Line 2 gets the handle attached to the client.

Then the if-check sees if the logged-in user is in that group or they're an admin.

Does that all make sense?


Edit: redirecting to the company page.

I've got a generic /portal/ page, and it shows a "Take me to my portal" link, that shows content based on which group a user is in. And then there's some generic contact info and stuff that applies to everyone. This could be better, but it was our solution for the first config.

2
  • Thanks SamC this looks very interesting- is that just one page per client? Not sure where 'associatedClient' fits in. It also feels like I'd be assigning the permission per content each time and make it hard for super admins to administer different company content. But happy for further illumination / explanation :)
    – joomkit
    Feb 5, 2020 at 20:16
  • Oh, skipped an item. I added a relationship field to each doc entry. So when add an entry, you select which client it goes to. When someone visits, page gets the client info and the client handle. Then checks permissions against the handle. The magic bit is that you've got a handle in a regular entry field that matches against the handle in the groups.
    – SamC
    Feb 6, 2020 at 14:22
1

Hi extending permissions on a group level is a first approach, here is a piece of code that create group permissions for each entry, it would be easy to customize it to allow only top level entries. It is based on cvraft cms extending permissions tutorial https://craftcms.com/docs/4.x/extend/user-permissions.html#requiring-permissions

   
        $entries = \craft\elements\Entry::find() ->all();

Event::on(
                UserPermissions::class,
                UserPermissions::EVENT_REGISTER_PERMISSIONS,
                function (RegisterUserPermissionsEvent $event) use ($entries) {


                 $entryPerms=[];
                    foreach ($entries as $entry) {
                    if ($entry->title)    $entryPerms[  'WaveEntryAccess' . $entry->id]=
                           [
                                'label' => $entry->title
                            ] ;
                 }
            $arrPerm = array(
                'permissionName' => [
                    'label' => "Wave Member access",
                    'nested' => $entryPerms
                ],
            );
                    $event->permissions['Member restricted access'  ]  =
                        $arrPerm ;
                }
            );

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.