其他分支中的名称和名称空间相同

验证模块的辅助功能。根据用户名登录或注册当前用户。无论哪种方式,都会填充全局$ user对象并执行登录任务。

文件


  • modules / 

    user / 

    user.module,第2329行

  • 启用用户注册和登录系统。


function user_external_login_register($name, $module) {
  $account = user_external_load($name);
  if (!$account) {

    // Register this new user.
    $userinfo = array(
      'name' => $name,
      'pass' => user_password(),
      'init' => $name,
      'status' => 1,
      'access' => REQUEST_TIME,
    );
    $account = user_save(drupal_anonymous_user(), $userinfo);

    // Terminate if an error occurred during user_save().
    if (!$account) {
      drupal_set_message(t("Error saving user account."), 'error');
      return;
    }
    user_set_authmaps($account, array(
      "authname_{$module}" => $name,
    ));
  }

  // Log user in.
  $form_state['uid'] = $account->uid;
  user_login_submit(array(), $form_state);
}

评论

mdshields的头像

在Drupal 7中,设置单点登录方案涉及核心user.module。此注释中的示例方案将介绍如何设置与user.module交互以启用SSO的模块。

首先,查看将在user.module中调用的main方法:

/**
 * Helper function for authentication modules. Either logs in or registers
 * the current user, based on username. Either way, the global $user object is
 * populated and login tasks are performed.
 */
function user_external_login_register($name, $module) {

为了达到调用此方法的目的,我们需要获取用户...用户名。我们可以从Drupal登录表单值中提取此值。为登录表单写一个钩子:

 /**
   * Implementation of hook_form_alter().
   * Change the normal form login form behaviour.
  */
function project_authentication_form_user_login_alter( &$form, $form_state )
{
    $form['#validate'] = array(  'user_login_name_validate', 'project_authentication_login_validate', 'user_login_final_validate' );
} 

通过在用户登录表单上设置挂钩,我们可以覆盖验证方法。在validate方法中,我们可以在外部服务器上验证用户名和密码。

/**
 * The project_authentication_auth() function attempts to authenticate a user off the external system using their e-mail address.
*/
function project_authentication_login_validate( $form, &$form_state )
{
    $username = $form_state['values']['name'];
    $response = project_authentication_check_user($username, $form_state['values']['pass'] );
    if ($response != false)
    {
        user_external_login_register( $username, 'project_authentication' );
        $account = user_external_load($username);
  	$form_state['uid'] = $account->uid;
    } // else drop through to the end and return nothing - Drupal will handle the rejection for us   
}

这里有一些特殊的步骤,让我们谈谈这个方法。
$ username从登录表单输入中提取。通过方法'project_authentication_check_user'验证该用户名以及与表单相关的密码:

function project_authentication_check_user($email,$password){
  try 
  {
    $result = ....
    if($result->size) {
        $info = ....
        return $info; 
    }
    return false;
  }
  catch (Exception $e) {
    watchdog('prjauth', 'Error %error_message.', array('%error_message' => $e->faultstring), WATCHDOG_NOTICE);
    return false;
  }
}

由于用户名和密码通过方法'project_authentication_check_user'传递,我们可以继续使用方法'project_authentication_login_validate'并最终调用:

user_external_login_register( $username, 'project_authentication' );

如果我们的系统中尚不存在该用户名,此方法将注册用户名...是的,我们能够将用户登录到我们系统中不存在的Drupal,因为它们存在于外部系统中。我们根据从'project_authentication_check_user'方法传递的信息注册它们。

登录用户基于传递给user_external_login_register方法的标志“project_authentication”。怎么可能?你有权访问Drupal数据库吗?看一下AUTHMAP表。

AUTHMAP表有一个名为MODULE的字段。值'project_authentication'存储在MODULE字段中。这样,字段AUTHNAME必须具有与传递给方法'user_external_login_register'的$ username值匹配的条目。根据该映射,用户登录Drupal。

当然,Drupal和外部系统之间需要有一些信任。这不在本教程之内,但您可以基于紧密耦合的系统获得信任,也可以使用SAML(http://en.wikipedia.org/wiki/Security_Assertion_Markup_Language)。利用Drupal提供的openID资产可能要容易得多:http://drupal.org/handbook/modules/openid

最后一个重要的注意事项是讨论方法'project_authentication_login_validate'。我们使用用户标识符填充$ form_state。

$account = user_external_load($username);
$form_state['uid'] = $account->uid;

我们这样做是因为我们的登录表单钩子的一部分涉及'user_login_name_validate'。这是被调用的,因此在验证完成后不会调用表单提交,因为方法'user_external_login_register'已经为我们调用了表单提交。方法'user_login_name_validate'需要用户标识符才能运行,因此我们在完成'user_external_login_register'方法时填充form_state。

顺便说一句,我们用来获取用户标识符的方法'user_external_load'仍在引用AUTHMAP表。根据我们在SSO体验中使用的用户名,我们假设它在AUTHMAP.authname字段中是唯一的。

所以,就是这样。您认为还有什么可以做的吗?可能有。角色仍然需要处理。您可以使用角色映射映射外部用户,并在用户注册时手动编辑角色。

此外,当用户忘记密码时,他们实际上并不使用Drupal密码,因为它位于外部系统中。这将是即将推出的另一个教程。

xxronis的头像

干得好,谢谢。
我非常想听听外部注册用户的密码操作......

日Thnx

朱利安的照片

<?php
/**
   * Implementation of hook_form_alter().
   * Change the normal form login form behaviour.
  */
function project_authentication_form_user_login_alter( &$form, $form_state )
{
    $form['#validate'] = array(  'user_login_name_validate', 'user_login_authenticate_validate', 'project_authentication_login_validate', 'user_login_final_validate' );
}
?>
soulston的头像

将“user_login_authenticate_validate”添加到“hook_form_user_login_alter”数组似乎会阻止使用我的“module_login_validate”登录,无论它在数组中的哪个位置?

我最终不得不在外部呼叫响应后通过以下方式检查用户:

- user_load_by_name($ form_state ['values'] ['name'])
- user_authenticate($ user_loaded-> name,$ form_state ['values'] ['pass'])

然后

$ account = user_load($ uid); 
$ form_state ['uid'] = $ account-> uid;

fischeme的头像

我正在摸不着为什么有必要在你的project_exhentication_login_validate函数中设置$ form_state ['uid']的额外步骤,当它似乎已经在user_external_login_register中完成时 - 但我承认我可能在这里遗漏了一些东西。谢谢。

fischeme的头像

毋庸置疑,代码是必需的,或者即使在成功登录后你也会再次获得登录框(除非你在登录后使用触发器/动作之类的东西来重定向,这掩盖了问题)。似乎user_external_login_register中设置的$ form_state是一个局部变量,我们需要更新实际的登录表单,因此需要在外部函数中执行此操作。无论如何,希望这有助于拯救某人几分钟。

pminf的头像

但是由于登录表单的填充值 和附加值$form_state ['uid']

$form_state ['uid'] = $account->uid;
user_login_submit(array(), $form_state);

用户登录两次。他还将获得两个“foo登录”消息。user_external_login_register()

我只能在没有登录部分的情况下编写自己的函数来解决这个问题当然,仍然需要在自定义验证功能中进行设置my_module_user_external_register()$form_state['uid']

bpirkle的头像

我们使用LoginToboggan允许用户使用他们的电子邮件地址登录。LoginToboggan还使用自定义验证功能,该功能被代码覆盖。为了让一切都快乐,我们改为:

  if (($key = array_search('user_login_authenticate_validate', $form['#validate'])) !== FALSE) {
    $form['#validate'][$key] = 'project_authentication_login_validate';
  }
rizedr的头像

谢谢你的分享!

但是,有些人可能想知道如何连接到不同的数据库。它可能会有点棘手,但实际上你想的更容易。

这是您的settings.php(sites \ default \ settings.php)中数据库设置的外观

$databases = array (
  'default' => 
  array (
    'default' => 
    array (
      'database' => 'drupaldb',
      'username' => 'root',
      'password' => 'password',
      'host' => 'localhost',
      'port' => '',
      'driver' => 'mysql',
      'prefix' => '',
    ),
  ),
); 

现在,为了添加新的数据库连接,我们需要修改它,但不是很多。以下示例是与多个数据库连接(观察代码中的注释):

$databases = array (
  'default' =>  // main drupal db starts from here
  array (
    'default' => 
    array (
      'database' => 'drupaldb', // main drupal db name
      'username' => 'root', // main drupal db username
      'password' => 'password', // main drupal db password
      'host' => 'localhost',
      'port' => '',
      'driver' => 'mysql',
      'prefix' => '',
    ),
  ),'yourcustomdb' =>  // additional database starts here
  array (
    'default' => 
    array (
      'database' => 'database', // additional database name
      'username' => 'root', // additional database username
      'password' => 'password', // additional database password
      'host' => 'localhost',
      'port' => '',
      'driver' => 'mysql',
      'prefix' => '',
    )
  ),
);

哦,我们已经建立了数据库。现在我们需要知道如何调用一个和另一个。不要惊慌,这很容易也很方便。在您需要它的模块中,它是这样的:

db_set_active('yourcustomdb'); // we call our custom db
$query = db_query("....."); // we do our query here...
db_set_active('default'); // we swich back to the drupal core db

// Now we do whatever we want with that query...

希望这有用。

CharlieCorsair的头像

谢谢,这很有意思。希望我的问题不是太基本,但作为Drupal的新手,我不知道在哪里放这个代码。我会把它作为我创建的新模块吗?

我觉得我不应该编辑核心文件,但有人可以指导我解释我将如何设置它吗?谢谢!

aaronce的头像

是的,模块是正确的地方。使用钩子和表单API是实现自定义功能的最佳方式。

CharlieCorsair的头像

谢谢......看起来没有捷径可以学习Drupal :)

balu.pathuri的头像

实际上我需要在我的登录注册器表单中添加我自己的自定义验证代码,以便如何进入drupal 7,以及如何链接到该文件。

fra_ben的头像

什么是“<外部系统信息>”?我已经尝试使用Drupal 7.39版本的代码,但它对我不起作用。如果这对我有用,我已经将$ result和$ info变量设置为true,但是当我尝试登录时它会返回登录错误。