We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 3749
    • 24,544 Posts
    You’re right about the process. If the user isn’t authorized to load a page, the page doesn’t exist and the user is forwarded to the error_page. One solution is to give anonymous users the load permission in the web context. Then the page should load and the snippet should run.

    There’s more info on this here: http://bobsguides.com/revolution-permissions.html (near the bottom of the page).
      Did I help you? Buy me a beer
      Get my Book: MODX:The Official Guide
      MODX info for everyone: http://bobsguides.com/modx.html
      My MODX Extras
      Bob's Guides is now hosted at A2 MODX Hosting
    • Hi Bob,

      Thanks for the tutorial about ACL. But I still don't get about redirecting user to 'unauthorized page' in the last section. Below the scenario:

      3 Users: anonymous (not loged-in), student, and teacher
      4 kind of resources: public, student only, teacher only, student & teacher only

      + Home (public)
      + /About Us/ (Public)
      + /Curriculum/ (student & teacher)
      + /Exam Page/ (student)
      + /Exam Creation Form/ (teacher)

      If user not logged-in, he/she must be redirected to log-in page. But if he/she logged-in already, for example as a student, then he/she must see "unauthorized" page when try to access teacher only page.

      Still not find straight solution for this scenario. Any ideas?

      Thank you,
      @zaenal
        zaenal.lokamaya
      • I see...

        $r = $modx->getObject('modResource', $unprotectedResourceID);
        //return resource object
        $r = $modx->getObject('modResource', $protectedResourceID);
        //return null, then modRequest send 404 error page
        


        I try to give (anonymous) user Load Only policy to all resources, but no luck. Give guest/anon to specific user group on-the-fly maybe can resolve this, but I won't go to that direction.
          zaenal.lokamaya
          • 3749
          • 24,544 Posts
          That should work, but the (anonymous) user would have to be a member of all the user groups.

          To just send not-logged-in users to the login page, BTW, you can add a tag for this snippet near at the top of the body section of the template (replace ## with the ID of the Login page):

          <?php
          $if (! $modx->user->hasSessionContext($modx->context->get('key'))) {
             $modx->sendRedirect($modx->makeUrl(##, "", "", 'full'));
          }
            Did I help you? Buy me a beer
            Get my Book: MODX:The Official Guide
            MODX info for everyone: http://bobsguides.com/modx.html
            My MODX Extras
            Bob's Guides is now hosted at A2 MODX Hosting
          • Oh, I see... the anonymous user actually has permission to access protected resources but had been redirected to login page because has no user-context-session.

            Thank's
              zaenal.lokamaya
            • Got straight method for redirecting user to login page, 404 page (Not Found) and 401 page (Unauthorized Access) without having to configure anonymous user and/or add snippet to protected resources.

              1. Add login_page key to system setting or context setting.
              2. Make sure we provide different page for error_page (404) and unauthorized_page (401) in system setting.
              3. Create a new plugin "checkPolicy" and attach 2 system event: OnWebPageInit and OnPageNotFound.

              After looking into modResource (/core/model/modx/modresource.class.php), I found that modx->resourceIdentifier may changes on the process.

              On OnWebPageInit event, modx->resourceIdentifier has just been set and provide the authentic value of the resource id. If the resource does not exist, it's simply return string value of the $PHP_SELF (only available when FURL is enabled); otherwise will be numeric value of resource id. On the process, when the resource not available for user, modRequest then forward the resource to 404 error_page (this process also changed modx->resourceIdentifier to error_page ID).

              So if we store resourceIdentifier value on OnWebPageInit, then we can use and compare it at the next event, OnPageNotFound. Then make a decision whether will be redirected to the login page or return 401 unauthorized_page instead of 404 error_page.

              Below the plugin code...

              <?php
              /**
               * checkPolicy plugin
               * ------------------
               * A general purpose for checking resource permission
               * and redirect user to login_page if required
               *
               * Requirement:
               * - Attach system event "OnWebPageInit" and "OnPageNotFound" onto this plugin
               * - Create new context/system setting: login_page (resource ID for login page)
               *   or set it on this plugin as scriptproperties, klik tab Properties > create property: login_page.
              **/
              
              //don't process this plugin on manager context or any context we want
              $excludeContext = array('mgr');
              if (in_array($modx->context->get('key'), $excludeContext)) return;
              
              global $checkResourceIdentifier;
              if (!isset($checkResourceIdentifier)) { 
                  //invoked on "OnWebPageInit" when $modx->resourceIdentifier has been set properly
                  //and save "default" resource ID on GLOBAL $checkResourceIdentifier
                  $checkResourceIdentifier = $modx->resourceIdentifier;
              } elseif (isset($checkResourceIdentifier) && intval($checkResourceIdentifier) > 0 && intval($checkResourceIdentifier) == $checkResourceIdentifier) { 
                  //invoked on "OnPageNotFound" after modRequest send 404 error
                  //and check $checkResourceIdentifier > 0 (resource exist but no privilege)
              
                  //get login_page, unauthorized_page and error_page
                  $E401 = $modx->getOption('unauthorized_page', $scriptProperties, 0);
                  $E404 = $modx->getOption('error_page', $scriptProperties, 0);
                  $login_page = $modx->getOption('login_page', $scriptProperties, 0);
                  
                  //don't process if "default" resource ID was error_page, unauthorized_page or login_page
                  if ($checkResourceIdentifier == $E401 || $checkResourceIdentifier == $E404 || $checkResourceIdentifier == $login_page) return ''; 
                  
                  //set $checkResourceIdentifier to 0, to make sure the plugin don't make any looping process
                  $checkResourceIdentifier = 0;
                  
                  if (!$modx->user->hasSessionContext($modx->context->get('key')) && $login_page > 0) {
                      //if not logged in? redirect to login page
                      $modx->sendRedirect($modx->makeUrl($login_page, "", "", 'full'));
                  } else {
                      //if logged in but have no privilege? send 401 unauthorized_page instead of 404 error_page
                      $modx->sendUnauthorizedPage();
                  }
              }
              


              Cheers,
              @zaenal

              [ed. note: lokamaya last edited this post 12 years, 6 months ago.]
                zaenal.lokamaya
                • 3749
                • 24,544 Posts
                I think you mean this:

                if ($checkResourceIdentifier == $E401 || $checkResourceIdentifier == $E404 || $checkResourceIdentifier == $login_page) return ''; 
                

                instead of this:

                if ($checkResourceIdentifier == $E401 && $checkResourceIdentifier == $E404 && $checkResourceIdentifier == $login_page) return ''; 


                That code will never execute unless your Login page is also the unauthorized and the error page, in which case you could use a much shorter test. wink
                  Did I help you? Buy me a beer
                  Get my Book: MODX:The Official Guide
                  MODX info for everyone: http://bobsguides.com/modx.html
                  My MODX Extras
                  Bob's Guides is now hosted at A2 MODX Hosting
                • Right, that's what I mean. Thanks...
                  The code above has been edited and reflect the recent changes.
                    zaenal.lokamaya
                    • 34120
                    • 236 Posts
                    Hope you don't mind me jumping in here, I'm really confused with this. I've managed to get the error_page page working so if a user tries to access a restricted page whilst logged out they will be redirected to the login screen. Since I got this working my login redirect has changed. I am using &loginResourceId=`27` but this seems to be overridden and I am now redirected to the unauthorized_page when I successfully login.

                    MODX Revolution 2.1.3-pl
                    Login 1.7.0-pl
                    • do you use snippet or plugin to redirect user to login page? you can't use both.
                        zaenal.lokamaya