Improve the default LoginForm

- has the fields and actions extracted to a separate method, so it's more easily overridable
- Moved the global variable $_REQUEST to getting the info from the controller
- Updated string variables to `::class`
- Updated RequiredFields to be set in the YML, so it's overridable/updatable from either Config or code
This commit is contained in:
Simon Erkelens 2017-04-14 16:21:38 +12:00 committed by Sam Minnée
parent 8ad9207d85
commit 3f1f9d04b7
3 changed files with 79 additions and 51 deletions

4
_config/security.yml Normal file
View File

@ -0,0 +1,4 @@
SilverStripe\Security\MemberLoginForm:
required_fields:
- Email
- Password

View File

@ -22,7 +22,7 @@ abstract class Authenticator extends Object
* *
* @var array * @var array
*/ */
private static $authenticators = array('SilverStripe\\Security\\MemberAuthenticator'); private static $authenticators = array(MemberAuthenticator::class);
/** /**
* Used to influence the order of authenticators on the login-screen * Used to influence the order of authenticators on the login-screen
@ -30,7 +30,7 @@ abstract class Authenticator extends Object
* *
* @var string * @var string
*/ */
private static $default_authenticator = 'SilverStripe\\Security\\MemberAuthenticator'; private static $default_authenticator = MemberAuthenticator::class;
/** /**
@ -113,7 +113,7 @@ abstract class Authenticator extends Object
return false; return false;
} }
if (is_subclass_of($authenticator, 'SilverStripe\\Security\\Authenticator') == false) { if (is_subclass_of($authenticator, self::class) == false) {
return false; return false;
} }

View File

@ -35,6 +35,12 @@ class MemberLoginForm extends LoginForm
*/ */
public $loggedInAsField = 'FirstName'; public $loggedInAsField = 'FirstName';
/**
* Required fields for validation
* @var array
*/
private static $required_fields;
/** /**
* Constructor * Constructor
* *
@ -69,8 +75,8 @@ class MemberLoginForm extends LoginForm
Requirements::css($customCSS); Requirements::css($customCSS);
} }
if (isset($_REQUEST['BackURL'])) { if ($controller->request->getVar('BackURL')) {
$backURL = $_REQUEST['BackURL']; $backURL = $controller->request->getVar('BackURL');
} else { } else {
$backURL = Session::get('BackURL'); $backURL = Session::get('BackURL');
} }
@ -84,14 +90,43 @@ class MemberLoginForm extends LoginForm
); );
} else { } else {
if (!$fields) { if (!$fields) {
$fields = $this->getFormFields();
}
if (!$actions) {
$actions = $this->getFormActions();
}
}
if (isset($backURL)) {
$fields->push(HiddenField::create('BackURL', 'BackURL', $backURL));
}
// Reduce attack surface by enforcing POST requests
$this->setFormMethod('POST', true);
parent::__construct($controller, $name, $fields, $actions);
$this->setValidator(RequiredFields::create(self::config()->get('required_fields')));
}
/**
* Build the FieldList for the login form
*
* @return FieldList
*/
protected function getFormFields()
{
$label = Member::singleton()->fieldLabel(Member::config()->unique_identifier_field); $label = Member::singleton()->fieldLabel(Member::config()->unique_identifier_field);
$fields = FieldList::create( $fields = FieldList::create(
HiddenField::create("AuthenticationMethod", null, $this->authenticator_class, $this), HiddenField::create("AuthenticationMethod", null, $this->authenticator_class, $this),
// Regardless of what the unique identifer field is (usually 'Email'), it will be held in the // Regardless of what the unique identifer field is (usually 'Email'), it will be held in the
// 'Email' value, below: // 'Email' value, below:
// @todo Rename the field to a more generic covering name
$emailField = TextField::create("Email", $label, null, null, $this), $emailField = TextField::create("Email", $label, null, null, $this),
PasswordField::create("Password", _t('Member.PASSWORD', 'Password')) PasswordField::create("Password", _t('Member.PASSWORD', 'Password'))
); );
$emailField->setAttribute('autofocus', 'true');
if (Security::config()->remember_username) { if (Security::config()->remember_username) {
$emailField->setValue(Session::get('SessionForms.MemberLoginForm.Email')); $emailField->setValue(Session::get('SessionForms.MemberLoginForm.Email'));
} else { } else {
@ -113,8 +148,17 @@ class MemberLoginForm extends LoginForm
) )
); );
} }
return $fields;
} }
if (!$actions) {
/**
* Build default login form action FieldList
*
* @return FieldList
*/
protected function getFormActions()
{
$actions = FieldList::create( $actions = FieldList::create(
FormAction::create('dologin', _t('Member.BUTTONLOGIN', "Log in")), FormAction::create('dologin', _t('Member.BUTTONLOGIN', "Log in")),
LiteralField::create( LiteralField::create(
@ -123,28 +167,8 @@ class MemberLoginForm extends LoginForm
. _t('Member.BUTTONLOSTPASSWORD', "I've lost my password") . '</a></p>' . _t('Member.BUTTONLOSTPASSWORD', "I've lost my password") . '</a></p>'
) )
); );
}
}
if (isset($backURL)) { return $actions;
$fields->push(HiddenField::create('BackURL', 'BackURL', $backURL));
}
// Reduce attack surface by enforcing POST requests
$this->setFormMethod('POST', true);
parent::__construct($controller, $name, $fields, $actions);
$this->setValidator(RequiredFields::create('Email', 'Password'));
// Focus on the email input when the page is loaded
$js = <<<JS
(function() {
var el = document.getElementById("MemberLoginForm_LoginForm_Email");
if(el && el.focus && (typeof jQuery == 'undefined' || jQuery(el).is(':visible'))) el.focus();
})();
JS;
Requirements::customScript($js, 'MemberLoginFormFieldFocus');
} }
public function restoreFormState() public function restoreFormState()