adrianmak

any good way to redirect to original url from a custom login form ?

Recommended Posts

This is my original question asking for access control for a template

https://processwire.com/talk/topic/8847-redirect-to-a-url-in-the-access-tab-of-a-template/

Eventually, as of Soma suggestion, I implemented access control and redirection in template itself.

The problem is after a sucessful login, the $session ->redirect method only destinate to one assigned url (in my case it is the homepage).

Reading the api doc, the session redirect provide just a simple url redirection. NO MORE functionality provided.

Then I append a GET variable on redirect url

a page template  required a specific user role privilege

<?php

if (!$user->isLoggedin()) {
    /* get current page id for page redirection after a successful login */
    $pageId = $page->id;
    $session->redirect(($pages->get("template=login")->url . "?redirect=" . $pageId));   
} 

/* required user with role registered to view this template */
if ($user->hasRole("registered")) {
    $page->title;
    $page->body;
} else {
    $page->body = "Your account do not have enough access privileges to view this page.";
}
include('./main.php');

login form template

<?php
$pageID = $_GET["redirect"];

    $lang = ($user->language->name == 'default') ? '' : $user->language->name . '/';
    if ($user->isLoggedin()) {
        $session->redirect($config->urls->root . $lang);
    }

    if ($input->post->user && $input->post->pass) {
        $username = $sanitizer->username($input->post->user);
        $password = $input->post->pass;
        $pageID = $input->post->redirect;
        $redirectPage = $pages->get($pageID)->url;

        try {
            if ($session->login($username, $password)) {
                if ($redirectPage) 
                    $session->redirect($redirectPage);

                $session->redirect($config->urls->root . $lang);
            } else {
                $error = "Wrong username or password. Login failed.";
            }
        } catch (Exception $e) {
            $error = $e->getMessage();
        }        
    }

$form_title = __("Sign In");
$form_user = __("User");
$form_pass = __("Password");
$form_submit_btn = __("Sign in");
$form_error =  __("Login failed");


$page->title = "User Login";
$page->body .= "
<div class='container'>
    <div class='col-md-12'>
        <div class='login-box'>
        <div class='panel panel-default'>
            <div class='panel-heading'>
                <h3 class='panel-title'><span class='lock-icon'></span><strong>$form_title</strong></h3>
            </div>
            <div class='panel-body'>
                <form role='form' action='./' method='post'>
                    <div class='message-error'>$error</div>
                    <input type='hidden' name='redirect' value=$pageID />
                    <div class='form-group'>
                        <label for='user'>$form_user</label>
                        <input type='text' name='user' id='user' class='form-control' placeholder=$form_user />
                    </div>
                    <div class='form-group'>
                        <label for='pass'>$form_pass</label>
                        <input type='password' name='pass' id='pass' class='form-control' placeholder=$form_pass />
                    </div>
                    <button type='submit' class='btn btn-sm btn-primary'>$form_submit_btn</button>
                </form>
            </div>
        </div>
        </div>
    </div>
</div>
";

include('./main.php');
?>

Retrieve the original url from the GET variable and  store in a form hidden field.

When  a successful login, checking this variable, if null , redirect to homepage or otherwise to that url


is it secure to implement in this way ?

Share this post


Link to post
Share on other sites

Your method seems secure enough. You are after all not sending a 404, so your user already knows that the url that they originally requested exists.

Another method is to use the session to store the redirect url. So in the restricted page you would do:

if (!$user->isLoggedin()) {
    // Store requested url in the session, then redirect
    $session->set('redirect', $page->url);
    $session->redirect($pages->get('template=login')->url);
}

and on the login page you could have

// Edit: This code is not correct as-is, please note Soma's post below including the try-catch block around the login code!

<?php

    if ($user->isLoggedin()) {
        $session->redirect($pages->get('/')->url);
    }

    if ($input->post->user && $input->post->pass) {
        $username = $sanitizer->username($input->post->user);
        $password = $input->post->pass;

        if ($session->login($username, $password)) {
            if ($redirectUrl = $session->get('redirect')){
                $session->remove('redirect');
                $session->redirect($redirectUrl);
            } else {
                $session->redirect($pages->get('/')->url);
            }
        } else {
            $error = "Wrong username or password. Login failed.";
        }
    }

  • Like 3

Share this post


Link to post
Share on other sites

For a very elegant solution you could change the behaviour of the access control via hooking into the execute function of the ProcessPageView module. You'd either have to modify the behaviour of the checkAccess function (which isn't hookable, but you can define a replacement in your hook) to change the way the redirect url option on the existing templates behaves, or you could add an additional method by hooking into the ProcessTemplates module as well.

I've got an example on one of my boxes, but can't access the files from here - will try and remember tonight.

The usual disclaimer about relying on hooks as a way of changing core behaviour potentially causing issues in future releases applies.

EDIT: The solution becomes elegant when utilising ESRCH's approach in the hook, in addition to modifying the login behaviour accordingly to handle the stored (or not) redirect session variable.

Share this post


Link to post
Share on other sites

@ESRCH

That login code will throw error if you login 3 times with wrong credentials... I already tried to put a note in those various (dozens already and lost track of) threads that use this "exact" frontend login code, which works but has one flaw. Problem is that once the login throttle kicks in you're left with a exception error. It's not obvious and I think posting that code in the forum over and over just creates problems in the long run for everyone copy paste such code. Funny thing is that the code originally is from Ryan himself.

Either Ryan should change the behaviour of the throttle code or you need to use this code instead with a try catch to catch the login throttle error:

if ($user->isLoggedin()) {
    $session->redirect($pages->get('/')->url);
}

if ($input->post->user && $input->post->pass) {
    $username = $sanitizer->username($input->post->user);
    $password = $input->post->pass;
    
    try{
        $u = $session->login($username, $password);
        if ($u) {
            if ($redirectUrl = $session->get('redirect')){
                $session->remove('redirect');
                $session->redirect($redirectUrl);
            } else {
                $session->redirect($pages->get('/')->url);
            }
        } else {
            $error = "Wrong username or password. Login failed.";
        }
    } catch(Exception $e){
       $error = $e->getMessage();
    
    }
}
  • Like 5

Share this post


Link to post
Share on other sites

@Soma

Thanks for the correction, I wasn't aware of this (and I incorrectly changed adrianmak's code). I made an edit in my post so that others might look at your comment.

Share this post


Link to post
Share on other sites

Sorry for perhaps not understanding the above Soma (and others) post, but does anyone know if there is, ideally, a best practice way to have SessionLoginThrottle setup so it redirects to somewhere where a friendly error may be displayed, like the Maintenance Mode module can?

Context: I have a site on PW dev 2.6.17 and when it hit a session throttle problem (me logged in on one computer logging in or out too quickly on a 2nd I think at almost the same time (I wasn't trying to break it—honest)) the result was the generic empty white "Website has encountered an error it has been logged" type message.

Share this post


Link to post
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

  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By Marco Angeli
      Hi there,
      I added a ssl certificate to my site and I'd like to redirect every single http url to its new https version
      So I added this code in the .htacces file, after the RewriteEngine On :
      Redirect 301 /about https://www.mysite.it/about
      Unfortunately this is now working: I get the "too many redirects" error.
      The following code works, but it's a bulk redirection to the home page, something I don't want for SEO reasons (https://moz.com/blog/save-your-website-with-redirects😞
      RewriteCond %{HTTP_HOST} mysite\.it [NC]
      RewriteCond %{SERVER_PORT} 80
      RewriteRule ^(.*)$ https://www.mysite.it/$1 [R,L]
      Any suggestions?
    • By matsn0w
      Hey all,
      I am working on a website and I want to style the login page, but I'm a bit confused. 
      I want either the existing login page styled in my own way using some CSS (I guess I prefer that) or I want to create a custom page with a form to login. (Which I could style too).
      I used the code from Ryan and Renobird posted here - which works great - but that doesn't replace the original login page. 
      Is there a way to some sort of 'disable' the original login?
      I hope my question is clear and thanks in advance,
      matsn0w
    • By Lex Sanchez
      Hi everyone:
      I do not know if someone before using ProcessWire with AWS CloudFront, currently I have problems with the login, it does not work for any reason, when I check in the logs generated by ProcessWire, it only indicates This request was aborted because it appears to be forged. (in /wire/core/SessionCSRF.php line 190).
      I have allowed CloudFront to forward all headers, cookies and allow all methods (GET, POST, PUT).
      When I perform the same process from the ip server if it works or from the balancer.
    • By flydev
      OAuth2Login for ProcessWire
      A Module which give you ability to login an existing user using your favorite thrid-party OAuth2 provider (i.e. Facebook, GitHub, Google, LinkedIn, etc.)..
      You can login from the backend to the backend directly or render a form on the frontend and redirect the user to a choosen page.
      Built on top of ThePhpLeague OAuth2-Client lib.
      Registration is not handled by this module but planned.
       
      Howto Install
      Install the module following this procedure:
       - http://modules.processwire.com/modules/oauth2-login/
       - https://github.com/flydev-fr/OAuth2Login
      Next step, in order to use a provider, you need to use Composer to install each provider
      ie: to install Google, open a terminal, go to your root directory of pw and type the following command-line: composer require league/oauth2-google
      Tested providers/packages :
          Google :  league/oauth2-google     Facebook: league/oauth2-facebook     Github: league/oauth2-github     LinkedIn: league/oauth2-linkedin
      More third-party providers are available there. You should be able to add a provider by simply adding it to the JSON config file.

      Howto Use It
      First (and for testing purpose), you should create a new user in ProcessWire that reflect your real OAuth2 account information. The important informations are, Last Name, First Name and Email. The module will compare existing users by firstname, lastname and email; If the user match the informations, then he is logged in.
      ie, if my Google fullname is John Wick, then in ProcessWire, I create a new user  Wick-John  with email  johnwick@mydomain.com
      Next step, go to your favorite provider and create an app in order to get the ClientId and ClientSecret keys. Ask on the forum if you have difficulties getting there.
      Once you got the keys for a provider, just paste it into the module settings and save it. One or more button should appear bellow the standard login form.
      The final step is to make your JSON configuration file.
      In this sample, the JSON config include all tested providers, you can of course edit it to suit your needs :
      { "providers": { "google": { "className": "Google", "packageName": "league/oauth2-google", "helpUrl": "https://console.developers.google.com/apis/credentials" }, "facebook": { "className": "Facebook", "packageName": "league/oauth2-facebook", "helpUrl": "https://developers.facebook.com/apps/", "options": { "graphApiVersion": "v2.10", "scope": "email" } }, "github": { "className": "Github", "packageName": "league/oauth2-github", "helpUrl": "https://github.com/settings/developers", "options": { "scope": "user:email" } }, "linkedin": { "className": "LinkedIn", "packageName": "league/oauth2-linkedin", "helpUrl": "https://www.linkedin.com/secure/developer" } } }  
      Backend Usage
      In ready.php, call the module :
      if($page->template == 'admin') { $oauth2mod = $modules->get('Oauth2Login'); if($oauth2mod) $oauth2mod->hookBackend(); }  
      Frontend Usage
      Small note: At this moment the render method is pretty simple. It output a InputfieldForm with InputfieldSubmit(s) into wrapped in a ul:li tag. Feedbacks and ideas welcome!
      For the following example, I created a page login and a template login which contain the following code :
      <?php namespace ProcessWire; if(!$user->isLoggedin()) { $options = array( 'buttonClass' => 'my_button_class', 'buttonValue' => 'Login with {provider}', // {{provider}} keyword 'prependMarkup' => '<div class="wrapper">', 'appendMarkup' => '</div>' ); $redirectUri = str_lreplace('//', '/', $config->urls->httpRoot . $page->url); $content = $modules->get('Oauth2Login')->config( array( 'redirect_uri' => $redirectUri, 'success_uri' => $page->url ) )->render($options); }
      The custom function lstr_replace() :
      /* * replace the last occurence of $search by $replace in $subject */ function str_lreplace($search, $replace, $subject) { return preg_replace('~(.*)' . preg_quote($search, '~') . '~', '$1' . $replace, $subject, 1); }  
      Screenshot
       



    • By dragan
      If I have two PW sites that sit in separate folders, I can't be logged-in in both sites.
      e.g.
      site.com/project-a/pw-admin-slug/
      site.com/project-b/pw-admin-slug/
      If I login to project-a, then also login to project-b, get back to the first site, I have to login again.
      Is the cookie / session mechanism storing my domain? If it does, and it's meant to be some sort of security enhancement, it should not check my domain, but root-URL of the PW-installation. (strangely, this doesn't happen on localhost)
      Is it possible to prevent that behavior? Often I have two sites open (e.g. check to see if I have the same CKEditor setup and quickly copy and paste it, or copy a user-role)