Front end login

Hi,

I have setup a multilingual site using Kirby 3 (3.0.3), and the Thinking3 theme.
The theme developer has provided me with a patch to make the theme multilingual as well.
Now I would like to restrict access to the blog page and it’s articles, so I can make these availabe for members only.

I have followed the access restriction guide and the login page is loading. However, login from the front-end does not seem to work.
I enabled debugging, and I get an error on the username (email address)
Also a note: the debugger exposes the password in plaintext, which is not optimal for a production site.

/www/site/controllers/login.php
line 17: if ($user = $kirby->user(get('username')) && $user->login(get('password'))) {
error message: Error - Call to a member function login() on null

One thing I noticed about the above error is that the webroot /www/ is listed for the login controller.
Caching is not enabled.

  • Any tips are welcome.

The login is available at unlisted page:
https://waucomont.eu/en/login
and also in the Dutch version of the site.

The Blog template has <?php if (!$kirby->user()) go('/') ?> added at the very top of the blog template, and routes to / if not logged in, so this is OK, but not very elegant.

  • Is there a way to hide the Blog menu item for site visitors that have not logged in?
  • Alternatively, is it possible to turn the login into a snippet, that I could display on the blog page, or in the sidebar, for non-logged in users only?
  • If not I will change the redirect

Hi @starfire43 Welcome to the Kirby community.

  1. Yes, you can hide the blog menu entry by using the same condition. Example navigation:

      <nav id="menu" class="menu">
        <?php foreach ($site->children()->listed() as $item): ?>
        <?php if (! $item->is(page('blog'))): ?>
            <?= $item->title()->tolink() ?>
           
        <?php else: ?>
            <?php if ($kirby->user()): ?>
              <?= $item->title()->tolink() ?>
            <?php endif ?>
        <?php endif ?>
        <?php endforeach ?>
        <?php if ($user = $kirby->user()): ?>
          <a href="<?= url('logout') ?>">Logout</a>
         <?php endif ?>
      </nav>

You can put the login form into a snippet, yes. If you want to have the login on the blog page, you don’t need the login page. You could then point the form’s action to the blog page and put the controller stuff into the blog controller instead.

Debugging shouldn’t be active on a production site and errors be logged to the error log instead.

Hello Sonja,

Thanks for the tips. I still have to figure out why the front-end login of the admin user is not working. I have created a test user in group “member” and will test also with that one, but there shouldn’t be a difference.

Where can I find the error log. I couldn’t find a reference to this in the documentation.
https://getkirby.com/docs/guide/troubleshooting/debugging would be a useful place to have this info.

I will test the recipe again and let you know my findings. As regards the PHP error log, that is a server thing and the location can vary, sometimes it doesn’t even exist by default or you have to set a location in your php.ini first. You can usually find info about this in the hosters documentation.

But the important part of my message was that error logging to the screen should be off on a production server.

And yes, form data is sent as plain text. That’s why using TLS is so important.

See also this cookbook recipe: https://getkirby.com/docs/cookbook/php/debugging-basics how to set error logging in your .htacess if there is no log file.

1 Like

Shouldn’t it be action="..." in the HTML form?

image

Good point, and should be corrected. But the action attribute will be ignored in this case and default to the current page.

And the controller does send an answer, displaying the error message like intended when entering a wrong user name and password.

@starfire43 Have you been able to sort this out?

Hi @Sphex Thanks for pointing out the form action error.
@texnixe I have followed the exact instructions as in https://getkirby.com/docs/cookbook/security/access-restriction, only modifying the page layout to match the theme I’m using.

So I guess the error is in the Kirby documentation:
/site/templates/login.php

<form method="post" action"<?= $page->url() ?>">

This should be

<form method="post" action="<?= $page->url() ?>">

I have now added the ‘=’, but I still receive an error when trying to login on the front-end.

I also checked server error logs, and it seems PHP 7.2 doesn’t like comma’s and semicolons in the config.

[Fri Mar 15 20:52:07.113353 2019] [:error] FastCGI: server "/var/run/php72-cgi/php-cgi" stderr: PHP message: PHP Parse error:  syntax error, unexpected end of file, expecting ';' in /www/site/config/config.php on line 29, referer: https://waucomont.eu/en/login

Here is my current config:

<?php

return [
    'debug' => false,
    'languages' => true,
    'routes' => [
        [
            'pattern' => 'home/(:any)',
            'action'  => function () {
                return go('home');
            }
		],
		[
			'pattern' => 'logout',
			'action'  => function() {
				if ($user = kirby()->user()) {
				  $user->logout();
			}
				return go('login');
			  }
		],
    ],
    'bnomei.robots-txt.sitemap' => 'sitemap.xml',
    'omz13.xmlsitemap' => [
        'excludeChildrenWhenTemplateIs' => ['default'],
        'disableImages' => true,
      ]
];

The error.log contains errors on the ; in the last line. I moved the semicolon to the last config line (has no effect on Kirby functioning as far as I can see.
The access.log shows an internal server error for the POST

[15/Mar/2019:21:06:18 +0100] "POST /en/login HTTP/1.1" 500 1070 "https://waucomont.eu/en/login" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:65.0) Gecko/20100101 Firefox/65.0" 3229 1260

I will attempt further troubleshooting this weekend.

Your routes are not quite correct, because you are on a multi-language site and the routes therefore must contain the language code.

@texnixe Thanks for the hint. From the error logs I already suspected a routing issue but I couldn’t think of a solution.

I found a tip on https://getkirby.com/docs/cookbook/i18n/filter-by-language.
However adding that to my login controller doesn’t seem to work.
Here is what I tried in the login controller:

<?php

$translatedPages = page('login')->children()->filter(function ($child) {
  return $child->translation(kirby()->language()->code())->exists();
});

return function ($kirby) {

  // don't show the login screen to already logged in users
  if ($kirby->user()) {
    go('/');
  }

  $error = false;

  // handle the form submission
  if ($kirby->request()->is('POST') && get('login')) {

    // fetch the user by username and run the
    // login method with the password
    if ($user = $kirby->user(get('username')) && $user->login(get('password'))) {
      // redirect to the homepage
      // if the login was successful
      go('/');
    } else {
      // make sure the alert is
      // displayed in the template
      $error = true;
    }

  }

  return [
    'error' => $error
  ];

};

In the multilingual template I received from Florian Kueker I have seen similar code in e.g. the blog controller:

$all_articles = $page->children()->listed()->filter(function ($child) { return $child->translation(kirby()->language()->code())->exists(); })->sortBy('date')->flip();

However I don’t know in which place in the login controller I should add the filter, and how.
Little bit stuck with this to be honest. Also spent already quite some time to get basic functionality like a login to work.

I am wondering why multilingual setup is so difficult to implement.
Found also Filter child pages by available translations where this was discussed for #kirby-2. Perhaps i can use a site-wide filtering?

You don’t need any filters, you have to modify your route patterns to include the language code, so instead of

'pattern' => 'logout'

it should be

'pattern' => ['en/logout', 'nl/logout'],

etc.

Or, for the logout, I’d do it like this, so you get the language code to redirect to the corresponding login page:

  'routes' => [
        [
            'pattern' => '(:any)/logout',
            'action'  => function($languageCode) {
              if ($user = kirby()->user()) {
                $user->logout();
              }
      
              go($languageCode .'/login');
      
            }
          ]
    ]

As regards the controller, you would have to redirect to the correct language version as well.

And there’s also an error in the recipe, must have missed to correct it.

This line

if ($user = $kirby->user(get('username')) && $user->login(get('password'))) {

is missing parenthesis and should be:


if (($user = $kirby->user(get('username'))) && $user->login(get('password'))) {

and then instead of go('/') in the controller, use go($kirby->languageCode(). '/');

1 Like

Hi @texnixe, thanks again for the swift response!
Login is fixed and working!

I had indeed blindly copied from the guide, and had missed that I needed to correct brackets :smiley:

I also changed the routing for non-logged-in visitors for the blog, so they get redirected to (multilingual) login, and same change done for the logout.

Thanks again!