Laravel Auth::attempt() 返回 false

Posted

技术标签:

【中文标题】Laravel Auth::attempt() 返回 false【英文标题】:Laravel Auth::attempt() returns false 【发布时间】:2017-05-11 14:33:54 【问题描述】:

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

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

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

如下所列,它有三个字段,分别是:

电子邮件 用户名 密码

我有一个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() 作为我的哈希方法。

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

我已经检查了以下链接:

Why is Auth::attempt always returns false

Laravel authattempt return false

附:由于我没有使用 Input 类,因此这些链接似乎很难理解。

【问题讨论】:

Laravel 自带 authentication controller。为什么不使用它而不是自己编写? 您的“登录”路线是使用 GET 方法吗?你能附上你的路线吗? 【参考方案1】:

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

让我们假设这种情况:一个请求被分派到具有nameemailpassword 字段的postRegister 方法。控制器创建用户并将其保存到数据库中。然后它将尚未通过身份验证的用户重定向到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 的工作方式。请求数据,you can't even redirect with custom headers。

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

1。使用闪存数据重定向

如果你想保留这个结构,你需要将postRegister()的请求数据刷入会话中(请求之间是持久的),然后在postLogin()方法中使用Session门面,@ 987654346@ 助手或实际的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() 方法的实现与不好的会话数据相结合。这样一来,您就无法独立于 postRegister 使用 postLogin

2。注册后立即登录用户

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

请注意 Laravel 自己的身份验证控制器 does it automatically。

顺便说一句,我的意思是:(理想情况下,这应该分解成多个方法,就像 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();

但是,它仍然远非完美!还有很多其他方法可以解决这个问题。一种可能是使用events,在失败时抛出exceptions 和redirecting using custom exceptions。但我不会去探索它们,因为已经有a solution perfectly designed for this。

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

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

【讨论】:

非常感谢您所做的一切,尽管解决方案 1 的结果并不是那么好,而且解决方案 2 遇到了很多错误... :( 不客气。您遇到了什么类型的错误? 我仍然得到解决方案 1 的“失败”(闪烁),并且当我执行“dd”凭据时,它正在为 postRegister() 工作,但当我在 postLogin() 中执行它时变为 null 太棒了! :) 你是对的;第一个解决方案的代码存在问题,我修复了它并解释了代码 cmets 的问题。请再次测试。第二个工作得很好。关于dd 的事情,这是预期的行为; postLogin中没有请求数据,所以都是null。我在答案中解释了原因。【参考方案2】:

您应该在每次插入一行 bcrypt(pass) 时散列您的密码。 Auth::attempt 假定从数据库中检索的密码是经过哈希处理的

【讨论】:

【参考方案3】:

Auth::attempt 使用\Hash::make($someString) 生成哈希。您也应该使用它来从相同的字符串生成相同的哈希(我假设种子与 bcrypt() 函数不同)。

所以改变这一行:

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

收件人:

$password = \Hash::make($request['password']);

【讨论】:

这太棒了,但它仍然没有解决我的问题,遗憾的是...... :( 嗯,你有没有尝试在更改代码后创建新用户?您确定用户正在保存到数据库中吗? 是的,我有。用户保存在数据库中,我将在上面的问题中发布更新... :) 两者都是一样的。 bcrypt function 只是相同功能的助手。 哦,好吧。然后我不知道它可能是什么。

以上是关于Laravel Auth::attempt() 返回 false的主要内容,如果未能解决你的问题,请参考以下文章

在 Auth::attempt() Laravel 5.1 中禁用重定向

Laravel Auth::attempt() 可以处理关系吗?

Laravel 5 Auth::attempt() 总是返回 false

Laravel 4 Auth::attempt() 总是返回 false

Laravel 4 Auth::attempt($userdata, false) 身份验证仍然保留

为啥 Auth::attempt 在 Laravel 5.3 中总是返回 false?