Wednesday, September 30, 2009

Customize your own SilverStripe Login Form and Authenticator

This is how I created a new Authenticator and associated Login Form. In this I was using another database table to use as the identifier.

First, create your new Login Form (MyLoginForm.php). This controls input fields redirects, etc.

<?php

class MyLoginForm extends LoginForm {

 protected $authenticator_class = 'MyAuthenticator';

 //we add fields in the constructor so the form is generated when instantiated
 function __construct($controller, $name, $fields = null, $actions = null, $checkCurrentUser = true) {
  //create your authenticator input here, e.g. username, but it could be any credentials
  //add your Authenticator to the form
  $fields = new FieldSet(
   new TextField('UserName', 'User Name'),
   new HiddenField("AuthenticationMethod", null, $this->authenticator_class, $this),
   new CheckboxField("Remember", "Remember me next time?")
  );

  $actions = new FieldSet(
   new FormAction('dologin', 'Log in')
  );

  //LoginForm does its magic
  parent::__construct($controller, $name, $fields, $actions);
 }


 // this function controls the redirect based on success/failure
 public function dologin($data) {
  if ($this->performLogin($data)) {
   Director::redirect(Director::baseURL());
  } else {
   Director::redirectBack();
  }
 }


 //call our own Authenticator
 public function performLogin($data) {
  if ($member = MyAuthenticator::authenticate($data, $this)) {
   $member->LogIn(isset($data['Remember']));
   return $member;
  } else {
   return null;
  }
 }

}

?>
 
Now, create your new Authenticator that calls the custom login form you created, takes the input and authenticates.

<?php
class MyAuthenticator extends Authenticator {

 //authenticate is called by the login form you created
 public static function authenticate($RAW_data, Form $form = null) {
  $SQL_user = Convert::raw2sql($RAW_data['UserName']);
  $member = DataObject::get_one("MyMember", "UserName = '$SQL_user'");
  if ($member) {
   return $member;
  } else {
   if ($form) $form->sessionMessage("That doesn't seem to be the right user name. Please try again.", "bad");
   return false;
  }
 }

 //Tell this Authenticator to use your custom login form
 //The 3rd parameter MUST be 'LoginForm' to fit within the authentication framework
 public static function get_login_form(Controller $controller) {
  return Object::create("MyLoginForm", $controller, "LoginForm");
 }

 //give a title to the MyAuthenticator tab (when multiple Authenticators are registered)
 public static function get_name() {
  return "User Name";
 }

}

?>

Lastly, register your new Authenticator in mysite/_config.php:

Authenticator::register_authenticator('MyAuthenticator');
(optional) Authenticator::set_default_authenticator('MyAuthenticator');
(optional) Authenticator::unregister_authenticator('MemberAuthenticator');

If you want to use your own form template, add it to /themes/mysite/templates/includes/MyLoginForm.ss

Notes:

  • This authenticator simply checks a fictional class 'MyMember' against the input username and passes if such a member is found. Obviously this is insecure in most cases. This is where you fill out the authenticate() method to authenticate securely using whatever credentials you receive from your custom login form.
  • More complicated functionality like redirecting to previous pages, redirecting based on groups, tracking login attempts, locking out users, adding non-existent users, etc are not handled. For inspiration on this look to the MemberAuthenticator and MemberLoginForm classes to see how SilverStripe handles it's own authentication and look into the External Authentication module.
  • I have another post on disabling the standard MemberAuthenticator for front-end users and creating a distinct access point for the CMS, using the standard MemberAuthenticator.

No comments:

Post a Comment