Jump to content

Login using e-mail rather than username (and general login issues)


mindplay.dk

Recommended Posts

I created a simple module that allows you to log in using your e-mail address rather than username:

https://github.com/m...lAuthentication

A couple of thoughts:

  1. This should be a built-in option in the login module, rather than an add-on - most sites have taught users to log in with their e-mail address. (I tend to forget what my username is - on most sites I don't have one!)
  2. The Session and ProcessLogin APIs need to be more extensible - for instance, to allow modifications to the form or fields. Modules like "login via Twitter" etc. will soon be something that people demand.

I wish the build...form() methods in PW were more generally open to hooks...

  • Like 5
Link to comment
Share on other sites

Looks good, thanks for making it!

This should be a built-in option in the login module, rather than an add-on - most sites have taught users to log in with their e-mail address. (I tend to forget what my username is - on most sites I don't have one!)

This login is meant for the admin, but when building your front-end site login, it's just as simple to use email address as it is name. Likewise, this is where I'm guessing the other types of logins (twitter, etc.) would be more likely to be implemented. But even if for admin, I really like that this module opens up the option to login by email and think others will too.

I'm not sure I agree that it should be built-in, as I want to pick a consistent standard and stay with it. So I actually think it's a perfect use case for a module, and think you solved it very nicely.

The only concern with using email addresses as logins is that they aren't guaranteed to be unique. After all, email is just a ProcessWire fieldtype (not something built into the pages table) and someone could be maintaining two accounts with the same email address (as I often do). So when building this functionality on the front-end, I usually do something like this:

$us = $users->find("email=$email");
foreach($us as $u) {
 if($u->pass === $pass) {
   // found the right one
 }
}
The Session and ProcessLogin APIs need to be more extensible - for instance, to allow modifications to the form or fields. Modules like "login via Twitter" etc. will soon be something that people demand.

I wish the build...form() methods in PW were more generally open to hooks...

I add hooks for anything that people want. But they don't get that way until someone asks for them. There is naturally a little more overhead associated with a hook function than there is with a native function, so I don't want to go off and make everything hookable just because it can be. It takes very little effort to make something hookable (just adding 3 underscores to the beginning) so it would be easy to get carried away with it. I can't predict everything that people would want to hook, so instead let the users decide what they want to hook and I add those 3 underscores and we're done. Easy. All you have to do is ask. If there is one thing I can do quickly, it's type 3 underscores. :)

Your ReflectionClass hack may not be necessary (though I did think it was quite a cool hack). Instead, I think you may be able to do this:

$form = $event->return;
$field = $form->get('login_name');
$field->label = $this->_('E-mail Address'); 
  • Like 1
Link to comment
Share on other sites

I see a big mindplay - ryan war, about what should be there and what not and how. Mindplay, Ryan has an answer to everything and it actually always makes sense, meanwhile he's a stubborn guy (which is good imo) as I knocked my head against him a couple times already. :P

Peace guys! :P

  • Like 1
Link to comment
Share on other sites

Hope my writing isn't coming off the wrong way -- this is good discussion and collaboration to me. I've been neglecting my duties at the forum for the last few days and trying to participate better now that I had a little break today. I'm having fun, learning and hopefully contributing something worthwhile too. Soma if you view this our any of our past interactions as confrontational in any way (which the word 'war' implies), I apologize because I felt much the opposite. Stubborn really? My wife will think that's hilarious, she thinks I'm a gullible pushover. :)

  • Like 1
Link to comment
Share on other sites

I actually think it's good, that we have someone like mindplay

I think it's great! And I hope some flaws can be found by doing this. It's a bit scary to think that someone alone has built such a perfect piece of software. If some flaws are found, I can sleep a bit better ;)

Ok, now seriously. It's great that someone can confront Ryan with other perspectives. Maybe in some cases, Ryan won't have a good answer and will think better about it. This can only make PW as good as it can get.

  • Like 1
Link to comment
Share on other sites

Aha - you can grab the form element via the form, by id! That'll come in handy, thanks :-)

I do think it would make more sense to have login via e-mail supported out of the box - logging in with username may be your personal preference, but it's just too exotic for mainstream. I forgot my username again today! ;)

If you offered an option to switch what field is used as the user-identity field, you could enforce uniqueness of that field, whether it's e-mail or username. That would definitely be safer and better than my hacky module. There's also going to be other issues with my module, like for one, the error-messages won't make much sense.

If I were to go ahead and implement this fully and correctly, following your code-standards and everything, and I submit a patch, would you at least consider it?

Link to comment
Share on other sites

If I were to go ahead and implement this fully and correctly, following your code-standards and everything, and I submit a patch, would you at least consider it?

Of course! I'm always glad anytime to get updates like this.

In this case, I wonder if it really should get down to the database level. For instance, supporting the option of a 'unique' index down to the table schema in text fields, which could then be inherited by the email field. For something beyond an individual site, uniqueness probably needs to be enforced down to the database level for any field used as a login identity. That's one reason why 'name' is good for this, because that uniqueness is already enforced. But the same could be done with email. I'm going to look at what changes might be needed at the lower level of text fieldtypes.

Link to comment
Share on other sites

  • 1 month later...

I think it just depends what method you are using for your custom login. But of course, if you are doing a custom login then you don't need this module as you can just retrieve the user by email address (rather than name) and compare the password that way.

Link to comment
Share on other sites

I've not tested this code but it's a first guess at how I might try this. It assumes $email and $pass hold sanitized input from a custom login form.

$who = wire()->users->get("email=$email")->name;
if($who) $user = wire()->session->login($who, $pass);
if($user) {
   // they authenticated ok...
}
else {
   // they didn't
}
  • Like 3
Link to comment
Share on other sites

  • 9 months later...

I have just one problem with this approach.

It's perfect for what I need for a site where customers can buy things/services as every email address is unique, however a username might not be! For example, if I have two customers called John Smith sign up, I have to do a check during registration to make sure that if there is a John Smith already that a number gets appended to their username (so john-smith-1 or something like that).

Feels a bit messy, but there really isn't any way around that I guess?

I'm being too picky though I think as even when a user edits their profile they don't need to know that behind the scenes their user page is stored with a name of john-smith-1

Okay, I'll shut up now since I've talked myself out of actually having a problem! :D

  • Like 1
Link to comment
Share on other sites

Feels a bit messy, but there really isn't any way around that I guess?

Usernames are just page names. If you aren't using them for user login, and don't want to append numbers, etc., you can always do something like this:

$user->name = $user->email; 

The "@" will get converted to a "-" (as will less commonly seen email characters like "+").

Link to comment
Share on other sites

  • 5 weeks later...

If it were me...

I would require a unique username, but also allow a user to login w/ their email address. 

For example, check for the username, if it's not found, check against the emails addresses in PW. I would not allow multiple accounts with the same email, however if you did want to, the passwords could determine which account would be logged into and if the passwords are the same... well login to the first account found. 

I just posted some comments about this in the wish list forum. Seems old fashioned not to allow email login, case insensitive usernames, and spaces in the user name (all of which could be easily turned on or off in the module settings). 

Eventually I'll fork the core login module if Ryan isn't interested in these ideas, because I need the login to be more user friendly. It's one of the biggest sources of frustration for people. Hopefully someday we'll have a way to do a one click login, maybe using a thumbprint.

As an aside, and not in response to Soma's comment, but rather in response to Ryan's comments... Ryan you are one of the most diplomatic and professional people I've encountered online. Your replies are generally quite polished and devoid of ego and I imagine clients love you, because you are an easy person to work with. 

To Soma's credit, I've seen a few threads on here where I was in full agreement with him and not with Ryan. Not because Ryan's answer isn't valid, but rather because my needs more closely matched Soma's. In these types of debates, there's never just one right answer, the right answer is always relative. 

What Ryan occasionally needs is someone to be the tie breaker. I've always found working with two other smart people (trusted advisors) to be very beneficial for this reason.

Link to comment
Share on other sites

Log in in with email address has more overhead so shouldn't be default.

Please let the system as it is. ( think ryan won't change it, cause it makes sense )

If your needs for the login with email is that high, write a module for it that hooks in. ( Session authenticate ( not shure about this hook ) )

side note:

There are a lot of developers to overcomplicate scripts. (count my self in) Ryan is the gatekeeper of no overhead & simplicity. let it be this way, please :-)

  • Like 3
Link to comment
Share on other sites

  • 5 months later...

It seems the module doesn't work in version 2.4. I tried it in a fresh 2.3 copy and it works as expected. In the current version i became a 'login failed' error where the '@' was converted in a '-' as Ryan wrote in a earlier post. Does anyone an idea how to fix this. I have a client who asks for the posibility to login users with email adresses...

Link to comment
Share on other sites

  • 11 months later...

I know this is a very late followup, but I recently posted an alternative over here:

https://processwire.com/talk/topic/1716-integrating-a-member-visitor-login-form/?p=89599

and

https://processwire.com/talk/topic/1716-integrating-a-member-visitor-login-form/?p=89616

Pros and cons to each version, so you should read all the posts in between as well. Personally I would go with the second one, just be aware that if you want it to work on the front-end you need to consider the name of your form fields.

  • Like 1
Link to comment
Share on other sites

  • 1 year later...

Bringing an old post back alive. I cannot get the user to authenticate and start a session for whatever reason in a custom login form. This form is for frontend users. I am hoping someone can see what I am missing. I am getting the user->name for the particular user though.

if($input->post->email && $input->post->pass) {
   $email = $sanitizer->email($input->post->email); 
   $pass = $input->post->pass;
   //allow for email login
   $us = $users->find("email=$email");
   foreach($us as $u) {
     echo $u->name . "<br />";
      if($u->pass === $pass) {
        echo "it matches" . "<br />";
        $u = $session->login($u->name, $pass);
      } else {
        echo "it does not" . "<br />";
      }
   }
}
Link to comment
Share on other sites

This seems to work, although I am not sure it is the best solution.

if($input->post->email && $input->post->pass) {
$email = $sanitizer->email($input->post->email); 
   $pass = $input->post->pass;

   //get user name
   $who = $users->get("email=$email")->name;
   if ($who) {
    //start a session if they exist
    $user = $session->login($who, $pass);
   }
   // if they are a logged in, it must match
   if ($user) {
   echo "it matches" . "<br />";
   } else {
   echo "it does not" . "<br />";
   }
}
Link to comment
Share on other sites

  • 10 months later...

if anyone wants to allow e-mail and name in admin login with PW 3.x (and i guess 2.8) the module from @mindplay.dk wasn't working for me, i guess because ProcessLogin::execute is not pageName sanitizing the name..

this one works for me (PW 3.0.51) and allows either name or e-mail (you could change the name label to reflect this too of course)

// change login name input label to e-mail-address
$wire->addHookAfter('ProcessLogin::buildLoginForm', function(HookEvent $event) {
	// on liner as we don't change anything else
	$event->return->get('login_name')->set('label', $event->_('E-Mail-Address'));
});

// hook into session::login to get user by mail
$wire->addHookBefore('Session::login', function(HookEvent $event) {
	// need to get email from $input as processLogin::execute is pageName sanitizing
	$email = $event->input->post->email('login_name');
	// stop here if login_name not a valid email
	if (!$email) return;
	// new selector arrays don't seem to work on $user so using $pages here
	$user = $event->pages->get([['email', $email]]);
	// if valid user set login name argument
	if ($user->id) $event->setArgument('name', $user->name);
});

i've got those in a _hooks.php included in my site/init.php but you could of course outsource it into a separate module etc..

  • Like 4
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
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...