Jump to content

Best approach to handling page view permissions in an app built on ProcessWire


thetuningspoon
 Share

Recommended Posts

I've been getting more and more into building full fledged web apps using PW as a framework. I use PW for data modeling and storage, user management, etc., and extend the Page class for different templates to add functionality to specific types of pages/data models. It is a very simple and powerful way to develop. 

However, one thing that I have struggled with is finding the right way to approach page view access for users of an application (This would also apply to a password-protected area of any PW site). I'm going to try and boil this down to the most simple, common scenario, and go from there:

 

I am building an app where every page in the app (except for the login screen) should be password protected. Should I...

 

1. Turn off page view access in the template access settings for the guest user and use the settings to redirect the user to a login page.

This has the drawback that you cannot disable guest view of the home page (a built-in PW limitation that seems a bit arbitrary). You are also limited in how you can define what to do when the page is not viewable (you must use the options provided in the admin interface), and you do not have the option of continuing to load the page with an alternate view (for example, a login form). Also, sometimes it requires configuring a lot of settings for a lot of different templates.  It also doesn't give you page-specific access control.

 

2. Leave the access settings wide open but write some code at the top of my template files, init.php, or ready.php to redirect users who are not logged in.

This has the disadvantage that it only applies if ProcessWire gets that far into the page load process, and it doesn't effect any other aspect of ProcessWire (for example, whether the page is available in a $pages->find()). If I wanted, I could allow anyone to reach any page and just show/hide the content based on the user's permissions or role. If the user doesn't have permission, I could keep them on the same page but show the login. Once they logged in, they'd be on the page they were originally looking for.

 

3. Write my own hook before or after Page::viewable and/or ProcessPageView::execute (or somewhere else?) to switch access on or off and redirect based on my own requirements.

This should be more reliable and secure than #2 and more flexible than #1, but it feels kind of like reinventing the wheel. Maybe the best approach is some combination of #1 and #3, with #2 reserved only for showing and hiding individual sections of a page that is already viewable.

 

I'd be very interested to hear how others are handling this.

Link to comment
Share on other sites

This topic reminded my on my tests with reference based access control. I don't know about performance / production usability... But maybe You would take a look.

https://bitbucket.org/pwFoo/accessbyreference/src/23e6a3597028da4021e3e348e4222a3ad77685a9/AccessByReference/AccessByReference.module?at=master&fileviewer=file-view-default

Manage view / edit permissions based on a reference chain page -> group -> user.

Wow... it's three years old... So it's untested with PW versions newer than three years :rolleyes:

  • Like 1
Link to comment
Share on other sites

Thanks, pwFoo, I will check that out.

Here's another problem with method #1: The redirect URL field in the template Access settings is not relative to the subfolder that you have PW installed in (if you have it installed in a subfolder). I always develop in a subfolder, making this feature impractical.

Link to comment
Share on other sites

Hi, just a hint:

I do not yet have much experience in this but for a similar (but not exactly same) use case I use @adrian's PageProtector module which supports locking down all Unpublished and/or Hidden pages just by clicking two checkboxes. I use it to protect areas of the website which are not yet ready to be seen by the public.
Of course in my case Published pages should be accessible by guests, but you might want to take a look at the module's code to see how he did it so that you can extend it to Published pages as well:

 

  • Like 2
  • Thanks 1
Link to comment
Share on other sites

An update:

I missed something in my last post. It is possible to use a page ID instead of a URL for the redirect in the template Access tab, which solves the subfolder issue.

However! For some strange reason, ProcessPageView::checkAccess specifically disallows using the home page (ID of 1) for the page ID here, silently overwriting it with page ID of the admin login form. This is unfortunate and ironic, as the enforced requirement of making the home page viewable to guests makes it a logical choice to serve as the login page for my application!

The other strange behavior here is that if you do use a page ID instead of a URL, ProcessWire does not actually do a $session->redirect() to the page at all, but just renders the content of the alternate page at the original requested URL. This seems to be how ProcessWire's admin login works as well. Perhaps a way to keep the user on the original requested page after they login? This was a surprise to me, as it's not mentioned in the UI.

I also found it interesting to discover that ProcessWire's own admin application shuns its own permissions system (or at least the template-level access part of it). If you look at the access settings for the Admin template, no view permissions are granted at all to any of the roles. Instead they are granted, I believe, based on the presence or absence of a single permission with the name of the process module associated with that page. This leads me to believe that I would be better off doing something similar in my own application.

 

The more I dive into this more confused I'm becoming. This is really the only part of ProcessWire that seems unintuitive to me. I get the permissions -> roles -> users bit, but the template level access permissions seem arbitrary to me. For example:

 

1. Why are only certain permissions available to set on a per-template basis?

2. Why are four of these permissions displayed prominently in a table while the rest are in the "additional edit permissions and overrides" section? 

3. What is it exactly that determines which permissions are special, and how do I create my own special permissions like these?

4. Why does the page-edit permission have 'sub-permissions' underneath it, but no other permission does?  Is there a way of structuring my own custom permissions in the same fashion?

Link to comment
Share on other sites

This post by Ryan partially answers your questions:

Regarding the admin login process, I do not know if it helps you or not but recently I used two hooks to use the admin login for frontend login as well:

<?php
$site_customers_pid = 'customers'
/* Redirects frontend user to /customers */
$wire->addHookAfter('Page::render', 'siteProtectPages', array('priority' => 654));
function siteProtectPages($event) {
	$current_page = $event->object;
	if ($current_page->template == 'admin') return; // ignore admin pages including admin login page
	if ($current_page->path() == "/{$site_customers_pid}/") {
		wire('session')->removeNotices(); // needed to clear "left over" notifications of the login page
	}
}

/* logout hooks for non admin users
 * see: https://processwire.com/talk/topic/15911-redirect-home-after-logout/#comment-142170
 */
$wire->addHookAfter("Session::logoutSuccess", null, "setRedirect");
function setRedirect(HookEvent $event) {
	if (wire('user')->hasRole('customer')) {
		wire('session')->redirect("/{$site_customers_pid}/");
	}
}

And "What to do when user attempts to view a page and has no access?" is set to: "/admin/login/". With this setup when the visitor goes to /customers/, they see the standard login form. After logging in, they get access to /customers/. I styled the admin header and login form with CSS and JS to make it more like the site's design.

I know that this is somewhat off topic but it might give you and idea or two.

Link to comment
Share on other sites

Here is a simple hook I put together to allow for a custom redirect when a page is not viewable:

/**
 * Automatically redirects users to the login page if they do not have view access to a page. To use, set "Show a 404 Page" in your template's Access settings.
 */
wire()->addHookBefore('ProcessPageView::pageNotFound', function($e) {
	$page = $e->arguments[0];
	if($page === null || $page instanceof NullPage) return; // This was a real 404, not caused by page access (have to check for NullPage, not just null as implied in ProcessPageView docs)

	$e->session->redirect($this->pages->get(1)->url, false); // Redirect to the home page (login)
});

This solves my immediate need. I can then hook Page::viewable() as needed and let PW take care of the rest.

I'm hoping @ryan may have some guidance on all of this.

  • Like 1
Link to comment
Share on other sites

46 minutes ago, szabesz said:

This post by Ryan partially answers your questions:

 

 

Thanks for that. I've read it over a few times now but I'm not quite getting it.

Quote

Having page-view, page-edit, page-create, page-add in the template access is actually unnecessary for us, but it does reduce the quantity of permissions and roles necessary to achieve a particular access control scenario 

How is this unnecessary? How else would one determine where each permission is applicable? Does he mean you could create a separate permission for each template, e.g. page-edit-home page-edit-basic-page, etc.?

 

Quote

I'd rather go in the opposite direction and reduce what permissions can be assigned at the template (by default), but make it definable. Imagine going to Modules > Process > ProcessTemplate > [edit module settings] and selecting from an asmSelect which permissions should be assignable at the template level -- a nice power user option?

Yes, yes, yes... THIS sounds like the type of solution I would expect from ProcessWire. Simple, powerful, and un-opinionated. What became of this?

  • Like 2
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By franciccio-ITALIANO
      Hello to all. I would like to create an app. So I need to learn at least one programming language. I got informed online, and discovered that javascript with node.js, is the revolution of recent years, because it's faster than php. I wonder: if I develop an app with javascript and with a javascript framework (e.g. Meteor), is there a way to integrate processwire work? I know that processwire supports the transformation of the site into an application, but would it be as simple as Meteor? With the Meteor framework I have my app online in 10 minutes, and without even knowing javascript! (Knowing javascript would serve to personalize it). I should then install the app in a SUB-DOMAIN. If I study php, instead, and if I use a php framework (e.g. Laravel), how long does it take to have my first working app? Is it easy to process Laravel's components? Is writing forms for processwire apps with php a very complex job? Is it better to use Meteor and start with javascript? What would you recommend?
    • By jonatan
      "Permission “page-sort” for template “ ... ” not allowed (requires “page-edit” permission)"

      – This lovely error message is thrown at me, if, as implied by it, I try to add (to my "editor" role) the permission "page-sort" for a specific template, without the permission "page-edit" enabled for the same template.
      Seems like it's been mentioned a few times before but never properly answered, by e.g. @Robin S ... :  
      "Allow the granting of page-sort permission independent of page-edit": https://github.com/processwire/processwire-requests/issues/29
       
       
       


      Why do I wanna do this?:

      I have a page tree structure  🌳  as so:

      ________________________

      Category [C1]
      – Page a [C1_p] – Page b [C1_p] Different category [C2]
      – Page c [C2_p] – Page d [C2_p] ________________________

      The page "Category" has the page-template "C1",
      the pages "Page a" and "Page b" both have the page-template "C1_p".
      The page "Different category" has the page-template "C2"
      the pages "Page c" and "Page d" both have the page-template "C2_p".
       
      The two pages called "Category" and "Different category" do not have any content, they only serve as containers for pages belonging to that category.
       
      I want my "editor" role not to be able to do anything at all with these pages "Category" and "Different category"; i.e. I do not want my editor to be able to edit, move, unpublish, hide, lock, delete (or do anything else to) these category pages. 
      – So, I want my "editor" role to have the "page-edit" permission for pages with the templates "C1_p" and "C2_p", but not for the pages with the category templates "C1" and "C2",
      Also, I want my "editor" role to be able to move the pages with the templates "C1_p" and "C2_p" within their parent-pages. 


      Problem:

      But if I just simply add the "page-edit" and the "page-move" permissions for the "C1_p" and "C2_p" templates, then, using the "editor" role, I am not able to move these "C1_p" (and "C2_p") -template-based pages. I can actually click "MOVE" next to them and then move them, but... then I will be met by the error message "You do not have permission to sort pages using this parent - /Category/".  
      – So, I try to add the "page-sort" (description: "permission to sort child pages") permission to the "C1" and "C2" templates... but then trying to do so I am met by the initially mentioned error message   ! Permission “page-sort” for template “C1” not allowed (requires “page-edit” permission)  . 
      And, as mentioned, I do not want my editor role users to be able to edit these category ("C1" and "C2") pages...
      – what to do about this? 😅 
       
      All the best,
      Jonatan 
    • By VeiJari
      Hi, this is the first we are trying to make a page that has only one type of user that has access to every page. 
      The other users should only have a given access to specific pages, not to the whole template.
      My structure
      -Field -Organisation -Project -Report I want that the "measurer" role only has access to "project x" and it's children, but no view access to every project, organisation or field. I've tried to do this with https://modules.processwire.com/modules/page-edit-per-user/ but it still needs a view access to the whole tree to see the "project x" page. Or is there something I haven't figured out?
      Maybe I have to make it via the API: a select field in the "organisation" template where the admins could add the users and then I use hook to update the privileges?
      Have you done something like this and how did you accomplish it?
      Any help would be appreciated.
       
    • By snck
      Hey there,
      for a client website I need to implement a "reviewer" role. "Reviewers" should be able to review new (unpublished) articles to give feedback to editors, but not have the permission to change them. 
      I built a new "reviewer" role that only has page-view permissions for the respective templates, but this permission does not include viewing unpublished pages. How can I grant them access to the unpublished articles without giving them page-edit permission?
      Cheers,
      Flo
    • By Pip
      Hi everyone!
      I'm trying out the Login/Register module for my site. Noted that the module assigns the newly registered user to login-register role. 
      Once you modify the login-register role's permissions, particularly adding page-edit, the new member role will be set to guest. 
      Thing is I'd like to grant my new users the power to create their own pages. Any advice? 
      Thanks. 
×
×
  • Create New...