Laravel Auth::attempt() 返回 false

新手上路,请多包涵

我是一名家庭爱好者,正在学习 Laravel,目前版本为 5.3 。我使用的是 Mac,既不是 homestead 也不是 vagrant

我目前正在开发一个使用登录和注册系统来创建用户的网站。

我使用 php artisan migrate 在本地操作我的数据库。

屏幕截图 2016 年 12 月 27 日下午 4.18.38.png

如下所列,它具有三个字段,即:

  • 电子邮件
  • 用户名
  • 密码

我有一个 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',
    ];

}

还有一个 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';
    }
}

?>

如您所见,我使用 bcrypt() 作为我的散列方法。

但是,这个问题是,它总是会导致失败。

屏幕截图 2016 年 12 月 27 日下午 4.41.38.png

我检查了以下链接:

PS 这些链接似乎很难理解,因为我没有使用 Input 类。

原文由 Programming_Duders 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 748
1 个回答

问题在于您在注册后将用户重定向到 login 路由的方式。您错误地假设 $request 数据将伴随重定向。

Let’s assume this scenario: A request gets dispatched to the postRegister method with name , email and password fields.控制器创建用户并将其保存到数据库中。然后它将尚未通过身份验证的用户重定向到 login 路由。 postLogin 方法被触发,但这次没有请求数据。结果, Auth::attempt($credentials) 失败了,你会在屏幕上看到讨厌的 Failure

如果您在创建数组后立即添加 dd($credentials) ,您会看到它没有值:

 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';
}

它将返回如下内容:

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

无论如何,您都无法使用自定义请求数据进行重定向(除非使用作为 URL 一部分的查询字符串)。这不是 HTTP 的工作方式。除了请求数据, 您甚至无法使用自定义标头重定向

现在您知道问题的根源是什么,让我们看看有哪些解决方法。

1. 使用闪存数据重定向

如果要保留此结构,则需要将 postRegister() 的请求数据闪存到会话中(在请求之间是持久的),然后在 postLogin() 方法中使用 Session 外观, session() 助手或实际 Illuminate\Session\SessionManager 类。

这就是我的意思:

我稍微修改了您的代码;删除了额外的变量,使其更简洁,等等。

 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';
}

我强烈建议您不要使用这种方法。这样,应该负责登录用户的 postLogin() 方法的实现与不好的会话数据相结合。这样,您将无法独立于 --- 使用 postLogin postRegister

2.注册后立即登录用户

这是一个稍微好一点的解决方案;如果您决定在注册后立即登录用户,为什么不这样做呢?

请注意,Laravel 自己的身份验证控制器 会自动执行此操作

顺便说一句,这就是我的意思:

(理想情况下,这应该分解为多种方法,就像 Laravel 自己的身份验证控制器一样。但这只是一个让您入门的示例。)

 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();
}

但是,它仍然 远非完美!还有很多其他方法可以解决这个问题。一种可能是使用 事件,在失败时抛出 异常使用自定义异常进行重定向。但我不打算探索它们,因为已经 有一个完美设计的解决方案

如果您想编写自己的身份验证控制器,那很好。一路上你会学到很多东西。但我强烈建议阅读 Laravel 自己的验证码,尤其是 RegistersUsersAuthenticatesUsers 特征,以便从中学习。

还有一个注意事项;您不需要 Illuminate\Auth\Authenticatable 您的 User 模型中的特征,因为它已经在扩展 Authenticatable 使用该特征。

原文由 sepehr 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题