I'm developing a custom module that should register and login users without use the native Drupal login/register form. The problem is that when I create an user in Drupal gestor, and try log it in, the session is created and user redirected to the administrative pages; when I create a user through my registration form (the user is created in the database and showed correctly in drupal gestor) and try to log it in, the user is redirected to the administrative pages (permissions and password were correctly validated) but the session is not created. As I see, this only happens with programmatically created accounts. If I try to log in an gestor created account, with my script, the session is created correctly.
The registration code is the following.
$userData = \Drupal::service('user.data');
$passI = \Drupal::service('password');
$user_data = array(
'name' => $form_state->getValue('nombres'),
'mail' => $form_state->getValue('correo'),
'pass' => $form_state->getValue('contrasena'),
'init' => $form_state->getValue('correo'),
'status' => 1,
'timezone' => 'America/Bogota',
'roles' => array('usuario_base','authenticated'),
);
$user = User::create($user_data);
$user->save();
$userData->set('my_module', $user->uid->value, 'apellidos', $form_state->getValue('apellidos'));
$userData->set('my_module', $user->uid->value, 'pais', $form_state->getValue('pais'));
$userData->set('my_module', $user->uid->value, 'ciudad', $form_state->getValue('ciudad'));
$company_data = array(
'estado' => true,
'razon_social' => $form_state->getValue('razon_social'),
'nit' => $form_state->getValue('nit'),
'resumen' => "",
'tipo' => $form_state->getValue('tipo'),
'producto' => $form_state->getValue('producto'),
'responsable' => $user->uid->value,
);
$company = Company::create($company_data);
$company->save();
$userData->set('my_module', $user->uid->value, 'empresa', $company->id->value);
if (!is_null($user) && !is_null($company)) {
$userr = User::load($user->uid->value);
user_login_finalize($userr);
$this->my_module_sso_user_login($userr);
} else {
$response = new RedirectResponse("registro");
$response->send();
$this->messenger->addWarning('Datos incorrectos', MessengerInterface::TYPE_WARNING);
}
The login code is the following.
public function submitForm(array &$form, FormStateInterface $form_state) {
parent::submitForm($form, $form_state);
$usuario = $form_state->getValue('usuario');
$contrasena = $form_state->getValue('contrasena');
$users = \Drupal::entityTypeManager()->getStorage('user')
->loadByProperties(['mail' => $usuario]);
$user_get = reset($users);
$roles_admitidos = array('administrator','base_user');
$passI = \Drupal::service('password');
if($this->hasPermission($user_get->getRoles(true),$roles_admitidos) || $user_get->id() == 1){
if ($passI->check($contrasena, $user_get->pass->value)) {
$user = User::load($user_get->uid->value);
user_login_finalize($user);
$this->my_module_user_login($user);
} else {
$response = new RedirectResponse("/colaborador/failed");
$response->send();
}
} else {
$response = new RedirectResponse("/colaborador/denied");
$response->send();
}
}
public function my_module_user_login($account)
{
$response = new RedirectResponse("/admin/my_module");
$response->send();
return;
}
public function hasPermission($roles,$roles_admitidos)
{
foreach ($roles as $rol){
if(in_array($rol,$roles_admitidos)){
return true;
}
}
return false;
}
The error I get is the following.
RuntimeException: Failed to start the session because headers have already been sent by "/home/xxxx/public_html/xxxx/vendor/symfony/http-foundation/Response.php" at line 1286. in /home/xxxx/public_html/xxxx/vendor/symfony/http-foundation/Session/Storage/NativeSessionStorage.php on line 141 #0 /home/xxxx/public_html/xxxx/core/lib/Drupal/Core/Session/SessionManager.php(164): Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage->start()
I don't know why are the headers sent only when the user is programmatically created.
hook_user_login
will be called when a user is logging in automatically, there is no need for you to call yourmy_module_user_login
directly, this will already happen. I would first advise naming the functions something different, unless it is intended to be an implementation ofhook_user_login
.RedirectResponse
is needed in a form submit either, over$form_state->setRedirect()
. I don't know the entire use case here, but you could also have implemented your ownUserAuth
service to streamline this, instead of ad-hoc forms.