Custom Login Page with username (instead of email) and password

Hi there,
I created a custom login page for pages with restricted access with the help of this cookbook-recipe:
https://getkirby.com/docs/cookbook/security/access-restriction

now I try to change the login-process because the client wants to login with username instead of email.

I found this post: Login with name instead of email
and tried to change the cookbook-code, but I run into the same problem. I get an error (debug mode: true) when the username does not exist or the password is wrong. the final solution-code was never posted, and I would be really happy, if we could solve the problem finally here.

here is my code:

<?php

return function ($kirby, $site) {

	$error = false;
	
	// go to this url if login was successful
	if(get('location') != '') {
	$redirect = get('location'); 
	} else {
		//go to the client page if login was successful but no location is found
		$redirect = $site->page('downloads'); 
	}
	
	// redirect immediately if user is already logged in
	if ($kirby->user()) go($redirect);
	
	// handle the form submission
	if ($kirby->request()->is('POST') && get('login')) {

		// try to log the user in with the provided credentials
		try {
			$username = get('username');
			$password = get('password');
			$user = $kirby->users()->findBy('username', $username);
			$userEmail = $user->email();
			
			$kirby->auth()->login($userEmail, $password);
			// redirect to the homepage if the login was successful
			go($redirect);
		} catch (Exception $e) {
			$error = true;
		}

	}

	return [
		'error' => $error
	];

};

thanks a lot!
bye, Matthias

Okay, I’m a step further now. This code seems to work and the user is able to use username or email for login an my custom login page.

<?php

return function ($kirby, $site) {

	$error = false;
	
	// go to this url if login was successful
	if(get('location') != '') {
	$redirect = get('location'); 
	} else {
		//go to the client page if login was successful but no location is found
		$redirect = $site->page('downloads'); 
	}
	
	// redirect immediately if user is already logged in
	if ($kirby->user()) go($redirect);
	
	// handle the form submission
	if ($kirby->request()->is('POST') && get('login')) {
		
		$username = get('username');
		$password = get('password');
		if(V::email($username)) {
			$userEmail = $username;
		} else {
			$user = $kirby->users()->findBy('username', $username);
			if (isset($user)) {
				$userEmail = $user->email();
			} else {
				$userEmail = '';
			}
		}
		
		// try to log the user in with the provided credentials
		try {
			$kirby->auth()->login($userEmail, $password);
			// redirect to the homepage if the login was successful
			go($redirect);
		} catch (Exception $e) {
			$error = true;
		}

	}

	return [
		'error' => $error
	];

};

I have two questions:

  1. Do you think the code is fine, or are there any problems I don’t see?
  2. There is still the Problem, that kirby allows the same username multiple times. Can you push me in a direction, how I can guarantee that the client cannot add users with a username, that is already used…?!

Thanks a lot!
Matthias

Maybe I missed it in the code or other discussions, but where are the usernames created? Is there a sign-up form on some page? In my mind, that would be the best place to check if a username exists already and then force the user to make a unique one.

I mean the name you can give to a useraccount… (in German it’s simply “Name:”)

In the meantime I found a solution myself with the use of hooks in config.php.

This is my solution:

'hooks' => [
		'user.create:before' => function (Kirby\Cms\User $user, array $input) {
			$newUsername = $user->name();
			if ($existingUsername = kirby()->users()->findBy('username', $newUsername)) {
				throw new ErrorException('Sorry! Der Benutzername ist leider schon vorhanden. Wähle einen anderen Benutzernamen.');
			}
		},
		'user.changeName:before' => function (Kirby\Cms\User $user, string $name) {
			$newUsername = $name;
			if ($existingUsername = kirby()->users()->findBy('username', $newUsername)) {
				throw new ErrorException('Sorry! Der Benutzername ist leider schon vorhanden. Wähle einen anderen Benutzernamen.');
			}
		}
	],

Can anyone give my a feedback?! Is it good to do it this way? Would there be other/better solutions?

thank and bye,
Matthias

Yes, that’s actually the only way to do it.