fiedsch/tokenlogin-bundle

Contao 4 Token Login Bundle

Installs: 21

Dependents: 0

Suggesters: 0

Security: 0

Stars: 4

Watchers: 2

Forks: 0

Open Issues: 0

Type:contao-bundle

0.1.3 2019-06-06 14:01 UTC

This package is auto-updated.

Last update: 2021-08-18 10:20:55 UTC


README

What it is

A module to allow Login with a token alone (as opposed to username+password).

To achieve this we do the following: username and token are semantically swapped as

  • we can not have one username having multiple passwords.
  • but we can have different user names always having the same password! The token which technically is the username will serve as the password.

How it works -- changes to the regular login process

  1. Extend the regular login module (ModuleTokenlogin extends \Contao\ModuleLogin)
  2. Provide a special login form that takes care of the changes. This form will not have a password field.
  3. Set the (POST-)value for password so the regular login module will be happy.
  4. (You) register a method for the importUser hook that creates a new member. See below for an example.

What you have to provide

  • You have to implement the Hook importUser and create a new Member there.

  • You have to have a list of valid tokens somewhere to decide if a login attempt should be considered valid.

An Example:

// your bundle's config.php

$GLOBALS['TL_HOOKS']['importUser'][] = array('MyVendor\MyBundle\MyHooks', 'myImportUser'); 
namespace MyVendor\MyBundle;

use Fiedsch\TokenloginBundle\ModuleTokenlogin;
use Contao\MemberModel;
use Contao\Encryption;
use Contao\System;

class MyHooks {
    /**
     * We want our users that log in via token to be in a special member group.
     * This is this group's ID.
     * You would typically want to make that configurable.
     */
    const TOKENUSER_MEMBERGROUP_ID = 1;
    
    /**
     * @param string $strUsername The unknown username.
     * @param string $strPassword  The password submitted in the login form.
     * @param string $strTable The user model table, either tl_member (for front end) or tl_user (for back end).
     * @return bool true if the user was successfully imported, false otherwise
     */
    public function myImportUser($strUsername, $strPassword, $strTable) {
        // front end only!
        if ($strTable == 'tl_member') {
            return $this->importFromTokenlist($strUsername, $strPassword);
        }
        return false;
    }
    
    /**
     * @param $strUsername string The unknown username.
     * @param $strPassword string The password submitted in the login form.
     * @return bool true if the user was successfully imported, false otherwise
     */
    protected function importFromTokenlist($strUsername, $strPassword) {
        try {
            // (0) Check for our special situation (just an additional test for the paranoid)
            if ($strPassword !== ModuleTokenlogin::TOKENUSERPASSWORD) { return false; }
    
            // (1) Check if the token supplied in $strUsername is found in our database
            // or token list. If not found: return false
            //
            // TODO: implement/fit to your needs.
            //
            // Always assume true in this test!
            //
            // (2) If the token is valid, create new member record -- which does not 
            // exist as otherwise myImportUser would not have been called
            // 
            // Thoughts: (maybe TODOs)
            // ignore case in $strUsername as otherwise xyz123 and YXZ123 will be two different users
            // (only applies if the above lookup for the token was case insensitive)
            
            $newMember = new MemberModel();
            $newMember->allowLogin = true;
            $newMember->password = Encryption::hash($strPassword);
            $newMember->username = $strUsername;
            $newMember->login = true;
            $newMember->firstname = "Token";
            $newMember->lastname = "User";
            $newMember->email = sprintf("%s@example.com", $strUsername);
            $newMember->groups = [ self::TOKENUSER_MEMBERGROUP_ID ];
            $newMember->dateAdded = time();
            $newMember->save();
            
            System::log(sprintf("created new member for token %s", $newMember->username), __METHOD__, TL_ACCESS);
            
            // (3) purge old entries? This might be a good place.
            
            // (4) return true to indicate success
            return true;
        } catch (\Exception $ignored) {
            return false;
        }
    }
}

Implementing in App Bundle

Add "autoload" section to composer (or extend it if already present):

   "autoload": {
       "psr-4": {
           "AppBundle\\": "src/AppBundle/"
       }
   }

Add file app/Resources/contao/config/config.php containing the hook declaration:

  $GLOBALS['TL_HOOKS']['importUser'][] = array('AppBundle\AppHooks', 'importUser'); 

Add file src/AppBundle/AppHooks.php and implement importUser there (see example above as a guide, where you obviously have to change the namespace to AppBundle and the class name to AppHooks).

Run composer dump-autoload.