Soy un aficionado hogareño y estoy estudiando Laravel, actualmente en la versión 5.3. Estoy usando una Mac, ni homestead ni vagrant.

Actualmente estoy trabajando en un sitio web que utiliza un sistema de inicio de sesión y registro para crear usuarios.

He usado php artisan migrate para manipular mi base de datos localmente.

Screen Shot 2016-12-27 at 4.18.38 PM.png

Como se enumera a continuación, tiene tres campos, a saber:

  • Email
  • Nombre de usuario
  • Contraseña

Tengo un modelo User (users.php):

<?php

namespace blog;

use Illuminate\Notifications\Notifiable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Contracts\Auth\Authenticatable;

class User extends Model implements Authenticatable {
    use \Illuminate\Auth\Authenticatable;

    use Notifiable;

    protected $fillable = [
        'username', 'email', 'password',
    ];

}

Y también, una clase UserController (UserController.php):

<?php

namespace blog\Http\Controllers;

use Auth;
use blog\User;
use Illuminate\Http\Request;

class UserController extends Controller {

    public function postRegister(Request $request) {
        $username = $request['username'];
        $email = $request['email'];
        $password = bcrypt($request['password']);

        $user = new User();
        $user->email = $email;
        $user->username = $username;
        $user->password = $password;

        $user->save();

        return redirect()->route('login');        
    }

    public function postLogin(Request $request) {

        $credentials = [
            'username' => $request['username'],
            'password' => $request['password'],
        ];

        if(Auth::attempt($credentials)) {
            return redirect()->route('dashboard');       
        }

        return 'Failure'; 
    }
}

?>

Como puede ver, estoy usando bcrypt() como mi método de hashing.

Sin embargo, este problema es que siempre resultará en una falla.

Screen Shot 2016-12-27 at 4.41.38 PM.png

He comprobado los siguientes enlaces:

PD Estos enlaces parecen muy difíciles de seguir ya que no utilizo la clase Input.

11
Programming_Duders 27 dic. 2016 a las 12:56

3 respuestas

La mejor respuesta

El problema es con la forma en que está redirigiendo al usuario a la ruta login después del registro. Asume falsamente que los datos de $request irán acompañados de la redirección.

Supongamos este escenario: una solicitud se envía al método postRegister con los campos name, email y password. El controlador crea el usuario y lo guarda en la base de datos. Luego redirige al usuario, que aún no está autenticado, a la ruta login. El método postLogin se activa, pero esta vez sin datos de solicitud. Como resultado, Auth::attempt($credentials) falla y obtienes ese desagradable Failure en la pantalla.

Si agrega un dd($credentials) justo después de crear la matriz, verá que no tiene valores:

public function postLogin(Request $request)
{
    $credentials = [
        'username' => $request['username'],
        'password' => $request['password'],
    ];

    // Dump data
    dd($credentials);

    if (Auth::attempt($credentials)) {
        return redirect()->route('dashboard');
    }

    return 'Failure';
}

Devolverá algo como esto:

array:2 [
  "username" => null
  "password" => null
]

No puede redirigir con datos de solicitud personalizados (a menos que con una cadena de consulta que sea parte de la URL), pase lo que pase. No es así como funciona HTTP. Solicite datos a un lado, ni siquiera puede redirigir con encabezados personalizados.

Ahora que sabe cuál es la raíz de su problema, veamos cuáles son las opciones para solucionarlo.

1. Redireccionar con datos flasheados

En caso de que desee preservar esta estructura, debe actualizar los datos de la solicitud de postRegister() en la sesión (que es persistente entre las solicitudes) y luego recuperarla en el método postLogin() usando Session fachada, session() auxiliar o la clase real Illuminate\Session\SessionManager.

Esto es lo que quiero decir:
( Modifiqué ligeramente su código; eliminé variables adicionales, lo hice un poco más limpio, etc. )

public function postRegister(Request $request)
{
    // Retrieve all request data including username, email & password.
    // I assume that the data IS validated.
    $input = $request->all();

    // Hash the password
    $input['password'] = bcrypt($input['password']);

    // Create the user
    User::create($input);

    // Redirect
    return redirect()
        // To the route named `login`
        ->route('login')

        // And flash the request data into the session,
        // if you flash the `$input` into the session, you'll
        // get a "Failure" message again. That's because the 
        // password in the $input array is already hashed and 
        // the attempt() method requires user's password, not 
        // the hashed copy of it. 
        //
        ->with($request->only('username', 'password'));
}

public function postLogin(Request $request)
{
    // Create the array using the values from the session
    $credentials = [
        'username' => session('username'),
        'password' => session('password'),
    ];

    // Attempt to login the user
    if (Auth::attempt($credentials)) {
        return redirect()->route('dashboard');
    }

    return 'Failure';
}

Le recomiendo no usar este enfoque. De esta manera, la implementación del método postLogin(), que se supone que es responsable de iniciar sesión en los usuarios, se combina con datos de sesión que no son buenos. De esta manera, no puede usar postLogin independientemente del postRegister.

2. Inicie sesión con el usuario justo después del registro.

Esta es una solución un poco mejor; Si decidió que necesita iniciar sesión en el usuario justo después del registro, ¿por qué no hacer eso?

Tenga en cuenta que el propio controlador de autenticación de Laravel .

Por cierto, esto es lo que quiero decir:
(Idealmente, esto debería dividirse en varios métodos, al igual que el propio controlador de autenticación de Laravel. Pero es solo un ejemplo para comenzar.)

public function postRegister(Request $request)
{
    $input = $request->all();

    $input['password'] = bcrypt($input['password']);

    User::create($input);

    // event(UserWasCreated::class);

    if (Auth::attempt($request->only('username', 'password'))) {
        return redirect()
            ->route('dashboard')
            ->with('Welcome! Your account has been successfully created!');
    }

    // Redirect
    return redirect()
        // To the previous page (probably the one generated by a `getRegister` method)
        ->back()
        // And with the input data (so that the form will get populated again)
        ->withInput();
}

¡Pero aún así, está lejos de ser perfecto ! Hay muchas otras formas de abordar esto. Uno podría estar usando eventos, arrojando excepciones en caso de error y redireccionamiento utilizando excepciones personalizadas. Pero no voy a explorarlos ya que ya hay una solución perfectamente diseñada para esto.

Si desea escribir su propio controlador de autenticación, está bien. Aprenderás mucho en el camino. Pero le sugiero que lea el código de autenticación de Laravel, especialmente AuthenticatesUsers rasgos para aprender de él.

Y una nota más; no necesita ese rasgo Illuminate\Auth\Authenticatable en su modelo User ya que ya se está extendiendo Authenticatable que usan ese rasgo.

4
Community 23 may. 2017 a las 10:30

Auth::attempt usa \Hash::make($someString) para generar el hash. También debe usar esto para generar los mismos hashes de las mismas cadenas (supongo que la semilla es diferente que con la función bcrypt()).

Entonces cambie esta línea:

$password = bcrypt($request['password']);

Para:

$password = \Hash::make($request['password']);
-2
sepehr 27 dic. 2016 a las 10:05

Debería cambiar su contraseña cada vez que inserte una fila bcrypt (pass). Auth :: intent asume que la contraseña que se recupera de la base de datos está cifrada

1
vachina 16 oct. 2017 a las 08:58