【问题标题】:Laravel Auth::attempt() returns falseLaravel Auth::attempt() 返回 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() 作为我的哈希方法。

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

我已经检查了以下链接:

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

【问题讨论】:

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

标签: php laravel authentication laravel-5


【解决方案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,在失败时抛出exceptionsredirecting 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 只是相同功能的助手。
    • 哦,好吧。然后我不知道它可能是什么。
    猜你喜欢
    • 2019-05-24
    • 2014-11-22
    • 1970-01-01
    • 2015-03-03
    • 2016-09-12
    • 2017-05-24
    • 2013-06-11
    • 2015-12-10
    相关资源
    最近更新 更多