[résolu] Connexion des utilisateurs d'une base externe

Information importante

En raison d'un grand nombre d'inscriptions de spammers sur notre site, polluant sans relache notre forum, nous suspendons la création de compte via le formulaire de "sign up".

Il est néanmoins toujours possible de devenir adhérent•e en faisant la demande sur cette page, rubrique "Inscription" : https://www.drupal.fr/contact


De plus, le forum est désormais "interdit en écriture". Il n'est plus autorisé d'y écrire un sujet/billet/commentaire.

Pour contacter la communauté, merci de rejoindre le slack "drupalfrance".

Si vous voulez contacter le bureau de l'association, utilisez le formulaire disponible ici, ou envoyez-nous un DM sur twitter.

Bonjour à tous,

1/Tout est dans le titre je crois. Je souhaiterais en fait utiliser les login, mot de passe d'une base externe situés sur le même serveur. En gros, je veux que les utilisateurs qui existent sur un autre site internet puissent se logger avec les mêmes identifiants et mot de passe actuels.
Est-ce possible en modifiant un fichier en php ou en passant par une autre solution (module, ...) ?

2/Deuxième chose : je veux également récupérer d'autres informations, comme le prénom, le nom, une photo par exemple de l'utilisateur qui pourront être modifiés via le compte sur le site internet développé avec drupal, mais qui devront être sauvegardés directement sur la base externe.

3/Pour résumé : est-ce que l'on peut utiliser une base externe pour gérer les comptes utilisateurs ?

Merci d'avance pour vos réponses...

Forum : 
Version de Drupal : 

Oui, c'est jouable sans trop de problèmes en ajoutant ton propre mécanisme d'authentification à la chaîne :

<?php
function mon_module_form_alter (&$form, $form_state, $form_id) {
     if (
$form_id == 'user_login_block' || $form_id == 'user_login' ) {
        if (isset(
$form_state['post']['name'])) {
            
$form['#validate'][] = _mon_module_authentification_externe();
        }
     }
}

function
_mon_module_authentification_externe ($form, $form_state) {
   
// Ici tu ajoutes ta connexion à ta base externe et l'authentification à partir
    // des données dans form_state. Si tout est OK, tu finis par return

    // Sinon...
   
form_set_error('error','Passera pas...');
}
?>

Ensuite tu implémentes un hook_user ($op==load) pour récupérer les données de ta base externe et les ajouter à l'objet user pour que le reste de drupal en bénéficie. Pour la sauvegarde, tu utilises $op==save.

Bonjour,

Désolé pour le retard de ma réponse. Merci beaucoup pour cette indication. Je n'ai pas encore trop touché aux fichiers php de Drupal, donc je ne sais pas du tout où se trouvent les fichiers pour la connexion des utilisateurs. Peut-être auriez-vous une précision à m'apporter sur le fichier php à modifier ? Et qu'est-ce que vous appelez un "hook_user" ? C'est un objet user j'imagine que l'on peut implémenter soi-même...

Merci.

Très bien. J'ai suivi le tutorial. Donc en fait, d'après ce que j'ai compris, quand on veut faire des traitements personnalisés, on passe généralement par la création de son propre module, en surchargeant des hook de drupal... En tout cas, très bon tuto, c'est une des facettes qui n'est presque jamais abordé dans les livres ou autres supports, et pourtant, pour les développeurs, ça me paraît maintenant être la base même de la création d'un site personnalisé.

Je vais essayer d'implémenter mon propre module pour les utilisateurs. Je vous tiens au courant en cas de problèmes.

Merci.

Bonjour Yoran,

juste une précision concernant la premiere partie de ton code :

[code]

<?php
function mon_module_form_alter (&$form, $form_state, $form_id) {
     if (
$form_id == 'user_login_block' || $form_id == 'user_login' ) {
        if (isset(
$form_state['post']['name'])) {
            
$form['#validate'][] = _mon_module_authentification_externe();
        }
     }
}

function
_mon_module_authentification_externe ($form, $form_state) {
   
// Ici tu ajoutes ta connexion à ta base externe et l'authentification à partir
    // des données dans form_state. Si tout est OK, tu finis par return

    // Sinon...
   
form_set_error('error','Passera pas...');
}
?>

[/code]

tu l'implante dans le fichier mon_module.module puis a la suite le hook_user ou bien dans un ficheir a part?

Merci

Tout dans le fichier mon_module.module. Si ce module grossis, j'ai tendance à ne laisser dans le .module que les hooks, et à déporter les fonctions "utilitaires" dans un mon_module.common.inc que j'inclus au début du module.

Merci pour cette précision. En parallèle puisque rien avoir avec ce post, j'ai suivi ton tuto pour contruire un module pour les blocs mais j'ai rien qui apparait dans /admin/build/blocks et si je mets un truc du style :

error_log("Ou es tu?");

j'ai rien dans le log d'apache2.

Tu as mis le error log où ça ? Le mieux dans un premier temps est de le mettre hors de toute fonction dans le fichier .module, de sorte à vérifier que le module est proprement activé. Ensuite dans la fonction hook_block, et vérifier que le log apparaît lorsque tu vas dans le panneau de configuration des blocs.

Autant pour moi, c'est moi qui est posté le message, et je n'avait pas donné ma solution. Voici le code de mon module qui permet de connecter un utilisateur d'une base externe à mon projet drupal :

<?php

/<strong>
 *
Connect an external user
 
* @param $form
 
* @param $form_state
 
* @param $form_id
 
* @return
 */
function
loginuser_form_alter(&$form, $form_state, $form_id)
{
   
   if (
$form_id == 'user_login_block' || $form_id == 'user_login')
   {
      if (isset(
$form_state['post']['name']))
       {
          if(
$form_state["post"]["name"] != 'admin')
           {
             
// Replace the default method to validate a user
              
$form['#validate'][1] = '_loginuser_authenticate_validate';
            }
      }
      else
       {
          return;
        }
      }
}

/</strong>
 *
Authenticate an external user
 
* @param $form
 
* @param $form_state
 
* @return
 */
function
_loginuser_authenticate_validate($form, &$form_state)
{
   global
$user ;
 
       
//Use external database
  
db_set_active('external_database');
 
// Search in external database
 
$results = db_query("SELECT * FROM external_user
  WHERE login = '%s' AND pass = '%s', "
,
   
$form['#post']['name'],md5($form['#post']['pass']));
  
  
$row = db_fetch_array($results) ;

 db_set_active('default');
   
  
// If external user exists
 
if($row)
   {
    
$resultsDrupal = db_query("SELECT * FROM {users} WHERE uid = %d ",
      
$row['id_user']);
       
$rowDrupal = db_fetch_array($resultsDrupal) ;
         
      
// If user's id exists in drupal
     
if ($rowDrupal)
       {
         
$login = $row['login'];
         
$pass = $row['pass'];
               
          
//If user's Drupal have a different login and pass
           
if($login != $rowDrupal['name']
         ||
$pass != $rowDrupal['pass'])
          {

            // Update drupal'login and drupal's pass
        
$success = db_query("UPDATE {users} SET login = '%s', pass =  '%s'
           WHERE uid = %d"
, $login, $pass, $row['id_user']);
               
         
$userinfo = array(
             
'uid' =>  $row['id_user']
           );
                
         
// User authenticates
        
$user = user_load($userinfo);
         
user_authenticate_finalize($userinfo);
      }
          else
           {
             
// Else user authenticates
            
user_authenticate($form_state['values']);
            }
      }
      else
       {
         
$login = $form['#post']['name'];
          
$pass = $form['#post']['pass'];
               
      
$userinfo = array(
        
'name' => $form['#post']['name'],
        
'pass' => $form['#post']['pass'],
        
'mail' => $row['email'],
           
'init' => $form['#post']['name'],
        
'status' => 1,
           
'uid' =>  $row['id_user'],
         
'access' => time(),
          
'timezone' => variable_get('date_default_timezone', NULL),
         
'language' => language_default()->language
        
);
            
              
          
$user = '';
             
          
// Create user in Drupal
          
user_save($user,$userinfo);
           
// Authenticate user
              
user_authenticate(array('name' => $login, 'pass' => $pass));
     }
  }
  else
   {
        
form_set_error('name', t('Sorry, unrecognized username or password.   <a  href="@password">Have you forgotten your password?</a>', array('@password' => url('user/password'))));
   }
}

/**
 * Hook_user
 * @param $form
 * @param $form_state
 * @return
 */
function loginuser_user($op, &$edit, &$account, $category = NULL)
{
   
   if(
$op == 'load')
    {
     
       if(
$account->uid != 1)
      {
         
db_set_active('external_database');
         
// Search in external database
        
$result = db_query("SELECT * FROM
            external_user WHERE id = '%d'"
, $account->uid);
         
          
$row = db_fetch_array($result) ;

          db_set_active('default');
           
          
$account->name = $row['Prenom'].' '.$row['Nom'];
         
$account->nom = $row['Nom'];
         
$account->prenom = $row['Prenom'];
        }
  }
 
   if(
$op == 'form')
    {
     
// Account information:
       
$form['information'] = array('#type' => 'fieldset',
          
'#title' => t('Informations générales'),
           
'#weight' => -11,
       );
      
      
$form['information']['nom'] = array(
      
'#type' => 'textfield',
    
'#title' => t('Nom'),
      
'#default_value' => $account->nom
     
);
    
      
$form['information']['prenom'] = array(
       
'#type' => 'textfield',
    
'#title' => t('Prenom'),
       
'#default_value' => $account->prenom
      
);
    
       return
$form;
  }
 
   if(
$op == 'validate')
    {
     
$error = false;
        if (!
strlen($edit['nom']))
      {
          
form_set_error('nom't('You must enter a username.'));
          
$error = true;
        }
      if (!
strlen($edit['prenom']))
       {
          
form_set_error('prenom't('You must enter a username.'));
           
$error = true;
        }
     
       if(
$error)
     {
          return;
        }
     
      
db_set_active('external_database');
     
$success = db_query("UPDATE external_user set
        Nom = '%s', Prenom = '%s'
     WHERE id = %d "
, $edit['nom'], $edit['prenom'], $account->uid);

       db_set_active('default');
       
       if(!
$success)
      {
         
form_set_error('', t('Une erreur est survenue lors de l\'enregistrement.'));
      }
     
   }
}

?>

En fait, je modifie une étape de la connexion d'un utilisateur pour vérifier si l'utilisateur existe bien dans ma base externe. Si il existe, je vérifie ensuite si il est créé dans Drupal, si ce n'est pas le cas, je le créé avec même login, mot de passe et même id. Si il existe dans Drupal, je vérifie que son mot de passe et login soient les mêmes, sinon, je les change dans Drupal avec les nouveaux. Ceci permet de connecter un utilisateur externe, et en plus de cela, d'obtenir et de connaître tous les nouveaux utilisateurs de ta base externe qui se connectent à ton projet Drupal.

En deuxième partie, c'est juste l'implémentation du hook_user, pour afficher et modifier des champs de la base externe.

Un très très grand merci à Yoran qui a un site bien expliqué et clair sur le développement de pleins de petits trucs sur Drupal. Idéal pour les développeurs qui ne veulent pas utiliser les modules Views, CCK et autres pour personnaliser au mieux leur application. Je vous invite donc à visiter son site très rapidement : http://arnumeral.fr/

Bon comme tu t'en doute je débute dans le dev donc mais questions seront peut être un peu tordues.

-Je ne vois pas dans ton code comme tu fais pour t'authentifier a ta BD externe afin de pouvoir faire les SELECT?

-Concernant la requête suivante :

$results = db_query("SELECT * FROM external_user
  WHERE login = '%s' AND pass = '%s', ",

external _user est un champ de ta BD externe?

en faites j'ai l'erreur suivante lorsque je vais dans le compte d'un User Drupal :

# warning: pg_query() [function.pg-query]: Query failed: ERREUR: la relation « external_user » n'existe pas in /includes/database.pgsql.inc on line 139.
# user warning: ERREUR: la relation « external_user » n'existe pas query: SELECT * FROM external_user WHERE id = '5' in /sites/all/modules/ConnectUser/connectuser.module on line 136.

Merci

Pas de soucis.

Donc, en fait, j'initialise au départ mes deux bases dans mon fichier "settings.php" qui se trouve dans "sites/default/" de ton application. Une des deux bases est la base par défaut de ton application Drupal, l'autre est ta base de donnée externe où tu vas récupérer les identifiants de connexion des utilisateurs. Pour que cela fonctionne, il faut bien sûr que tes deux bases soient sur le même serveur. Voici les deux lignes pour initialiser ces bases dans "settings.php" :

$db_url['default'] = 'mysql://username:username:password@localhost/databasename';
$db_url['external_database'] = 'mysql://username:username:password@localhost/externaldatabase';

Tu te douteras que je n'ai pas mis mes identifiants de connexion évidemment dans cet exemple. Il faut que tu les remplaces par les tiens.

Et donc pour utiliser la base externe, avant chaque requête j'utilise cette commande :

db_set_active('external_database');

Une fois que j'ai effectué ma requête sur la base externe, je reviens sur ma base par défaut qui est celle de Drupal, avec la commande suivante :

db_set_active('default');

Ton erreur peut provenir de 2 sources différentes :
- soit tu n'as pas effectué la connexion à ta base externe
- soit la table "external_user" n'existe pas dans ta base externe

Il faut bien sûr adapter tout ce code à ton application. C'était juste un exemple de mon module où j'ai changé les différents noms des tables et bases.

De rien.

Oui effectivement. Après je ne sais pas trop quel est le mécanisme pour faire communiquer deux bases sur deux serveurs différents. C'est un autre problème qu'un simple module sur Drupal. Peut-être existe-il une config spéciale sur Drupal... Il faudrait que tu te renseignes, ou que tu postes un nouveau sujet si tu ne trouves pas de solutions.

Normalement peu importe ou se trouvent les bases du moment que tu met correctement leur IP
Par ex localhost pour la bdd de drupal et 192.168.0.1 pour l'externe.

$db_url['default'] = 'mysql://username:username:password@localhost/databasename';
$db_url['external_database'] = 'mysql://username:username:password@192.168.0.1/externaldatabase';

Bonjour capoucho

en faite je voulais éxecuter un code similaire au tien voici :

<?php
/<strong>
*
Implementation of hook_help().
*/
function
custom_auth_help( $path, $arg )
{
    switch (
$path )
    {
        case
'admin/help#custom_auth':
        {
            return(
'<p>' . t('This module allows users who login with e-mail addresses to authenticate off an external system.') . '</p>' );


        }
    }
}

/</
strong>
   *
Implementation of hook_form_alter().
   *
   *
Change the normal form login form behaviour.
   */
function
custom_auth_form_user_login_alter( &$form, $form_state )
{
    unset(
$form['links']);
   
$form['#validate'] = array(  'user_login_name_validate', 'custom_auth_login_validate', 'user_login_final_validate' );
}

function
custom_auth_form_user_login_block_alter( &$form, $form_state )
{
  return
custom_auth_form_user_login_alter( $form, $form_state );
}

/<
strong>
*
The custom_auth_auth() function attempts to authenticate a user off the external system using their e-mail address.
*/
function
custom_auth_login_validate( $form, &$form_state )
{
   
$username = $form_state['values']['name'];

   
// In our case we're assuming that any username with an '@' sign is an e-mail address, hence we're going to check the credentials against our external system.
 
if ( strpos( $username, '@' ) !== false )
  {
       
// Look for user in external database
db_set_active('external_database');
 
// Search in external database
$results = db_query("SELECT * FROM {membre}  WHERE membre_mail ='%s', ",$form['values']['name']);
  
$row = db_fetch_array($results) ;
 
dsm($row);
 
db_set_active('default');
   
  
// If external user exists
   
if($row) {
           
           
           
               
user_external_login_register( $username, 'custom_auth' );
               
user_authenticate_finalize( $form_state['values'] );
            
// else drop through to the end and return nothing - Drupal will handle the rejection for us
       
}
    else
   {
        
form_set_error('name', t('Sorryyyys, unrecognized username or password.   <a  href="@password">Have you forgotten your password?</a>', array('@password' => url('user/password'))));
   }
 }
 else
    {
       
// Username is not an e-mail address, so use standard Drupal authentication function
       
user_login_authenticate_validate( $form, &$form_state );
    }
}

/</
strong>
*
The custom_auth_user() function gets called by Drupal after a new user has been added. If the e-mail address has
* already been set then we don't want to overwrite it, as the user is probably being added manually. Thankfully
* the only time a user can be added without the e-mail being set is when custom_auth_auth() gets run for a first-time
* user, at which point a user is inserted without an e-mail address. That is the case we'
re dealing with in this
* function.
*/
function
custom_auth_user( $op, &$edit, &$account, $category = null )
{
    switch(
$op )
    {
        case(
'insert' ): // This hook is called during the registration process, AFTER the new user has been added to the users table but BEFORE the roles are written to the users_roles table
       
{
            if ( empty(
$account->mail ))
            {
               
db_query("UPDATE {users} SET mail = '%s' WHERE uid = %d", $account->name, $account->uid);
            }
           
           
// Note: you can do other stuff here, like set the password to be the md5 hash of the remote password. This might be handy if you wanted to allow people to log on when the external system is unavailable, but, of course, it introduces the hassle of keeping the passwords in sync.

            // This is where we set that additional role to indicate that the user is authenticated externally. Note that EXTERNAL_AUTH_RID is undefined in this sample code but would normally be set to whatever Role ID is in the database. (So that is, create the new role, do a query to find the RID for that role and set EXTERNAL_AUTH_RID to that RID. Or just hard code it in the following line.)
           
$edit['roles'][EXTERNAL_AUTH_RID] = 'external_auth';
            return;
        }

        case(
'update' ): // This hook is called BEFORE the record in the database (or $account) has been updated
       
{
            if (
strpos( $account->name, '@' ) !== false )
            {
               
// If the user is identified by their e-mail address and they are trying to change their e-mail address, don't let them.
               
if ( strcmp( $account->mail, $edit['mail'] ))
                {
                    unset(
$edit['mail']);
                   
drupal_set_message( 'Sorry, users who use their e-mail address to login cannot change their e-mail address.', 'error' );
                }

               
// If the user is identified by their e-mail address and they are trying to change their password, don't let them.
               
if ( $edit['pass'] != '' )
                {
                    unset(
$edit['pass']);
                   
drupal_set_message( 'Please access the external system to change your password.', 'error' );
                }
            }

            return;
        }
    }
}
?>

mais en l’exécutant (j'ai mis un adresse mail a la place nom utilisateur de Drupal) il m'a affiche ca :

Sorryyyys, unrecognized username or password

je sais pas le problème : alors que j'ai bien configuré mon settings.php pour les 2 bases. C'est le select qui marche pas?

merci