Silverstripe Version: 4.5.0
For legacy reasons, our users need to be able to log on to Silverstripe with either an email or a username. (the login form is default, but they can enter a username instead of an email address if they wish).
Reading https://docs.silverstripe.org/en/4/developer_guides/security/authentication/ the page says:
“If only a subset of the supportedServices() will be provided by the custom Authenticator, it is advised to extend
SilverStripe\Security\MemberAuthenticator\MemberAuthenticator
, as that default contains all required methods already and only an override or follow up needs to be written.”
That sounded ideal to me, as presumably I’d just have to write my own LoginHandler and everything else would function as normal?
So I added this to mysite.yml:
SilverStripe\Core\Injector\Injector:
SilverStripe\Security\Security:
properties:
Authenticators:
MyAuthenticator: '%$SilverStripe\Security\MemberAuthenticator\MyAuthenticator'
I then created :
app/src/Extensions/MyAuthenticator.php:
namespace SilverStripe\Security\MemberAuthenticator;
use SilverStripe\Core\Injector\Injector;
use Psr\Log\LoggerInterface;
use SilverStripe\Security\MemberAuthenticator\MemberAuthenticator;
class MyAuthenticator extends MemberAuthenticator {
public function getLoginHandler($link)
{
return MyLoginHandler::create($link, $this);
}
}
app/src/Extensions/MyLoginHandler.php:
namespace SilverStripe\Security\MemberAuthenticator;
use SilverStripe\Security\MemberAuthenticator\LoginHandler;
use SilverStripe\Control\Controller;
use SilverStripe\Control\HTTPRequest;
use SilverStripe\Control\HTTPResponse;
use SilverStripe\Control\RequestHandler;
use SilverStripe\ORM\ValidationResult;
use SilverStripe\Security\Authenticator;
use SilverStripe\Security\PasswordExpirationMiddleware;
use SilverStripe\Security\IdentityStore;
use SilverStripe\Security\Member;
use SilverStripe\Security\Security;
use SilverStripe\Core\Injector\Injector;
use Psr\Log\LoggerInterface;
class MyLoginHandler extends LoginHandler
{
public function doLogin($data, MemberLoginForm $form, HTTPRequest $request)
{
// code in here to manipulate $data as needed
}
}
All of the above worked, I was able to change the login behaviour via doLogin() so that normal email addresses login with no change, and usernames lookup what the email should be and substitute accordingly.
The problem I can’t work out how to solve is that our Login Form is now being output twice. It’s the default Silverstripe form, we haven’t written a custom one. It also has extra output at the top of each one that looks like this, which didn’t output prior to my changes:
<ul>
<li><a href="/Security/login#MemberLoginForm_LoginForm_Tab">E-mail & Password</a></li>
<li><a href="/Security/login#MemberLoginForm_LoginForm_Tab">E-mail & Password</a></li>
</ul>
I went back and commented out all the code in MyAuthenticator.php, so it just reads:
namespace SilverStripe\Security\MemberAuthenticator;
use SilverStripe\Core\Injector\Injector;
use Psr\Log\LoggerInterface;
use SilverStripe\Security\MemberAuthenticator\MemberAuthenticator;
class MyAuthenticator extends MemberAuthenticator {
}
then did a /dev/build/?flush=all and I get the same behaviour - so it looks to me that the injector addition to mysite.yml and declaring “class MyAuthenticator extends MemberAuthenticator” is what is causing our LoginForm to glitch.
If anyone can suggest what I’ve done wrong it would be very much appreciated.
Do I have problem with namespaces, is my approach fundamentally flawed? I’m a bit thrown to be honest as it’s like the hard part worked fine (extending the login logic) but I can’t work out how to debug the glitchy login form!
Thanks!